Improve the broadcast ping mechanism and always run that as first thing.
parent
944731c171
commit
f3e465a551
|
|
@ -0,0 +1,51 @@
|
|||
#include "broadcastping.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QNetworkInterface>
|
||||
#include <QProcess>
|
||||
|
||||
BroadcastPing::BroadcastPing(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BroadcastPing::run()
|
||||
{
|
||||
qDeleteAll(m_runningPings.keys());
|
||||
m_runningPings.clear();
|
||||
|
||||
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||
if (!interface.flags().testFlag(QNetworkInterface::IsUp) || !interface.flags().testFlag(QNetworkInterface::CanBroadcast) || interface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
|
||||
continue;
|
||||
}
|
||||
foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) {
|
||||
if (addressEntry.broadcast().isNull()) {
|
||||
continue;
|
||||
}
|
||||
qCDebug(dcNetworkDetector()) << "Sending Broadcast Ping on" << addressEntry.broadcast().toString() + '/' + QString::number(addressEntry.prefixLength()) + "...";
|
||||
QProcess *p = new QProcess(this);
|
||||
m_runningPings.insert(p, addressEntry);
|
||||
p->start("fping", {"-a", "-c", "1", "-g", addressEntry.broadcast().toString() + "/" + QString::number(addressEntry.prefixLength())});
|
||||
connect(p, SIGNAL(finished(int)), this, SLOT(broadcastPingFinished(int)));
|
||||
}
|
||||
}
|
||||
if (m_runningPings.isEmpty()) {
|
||||
qCWarning(dcNetworkDetector()) << "Cound not find any suitable interface for broadcast pinging";
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
||||
void BroadcastPing::broadcastPingFinished(int exitCode)
|
||||
{
|
||||
Q_UNUSED(exitCode);
|
||||
QProcess *p = static_cast<QProcess*>(sender());
|
||||
QNetworkAddressEntry addressEntry = m_runningPings.take(p);
|
||||
qCDebug(dcNetworkDetector()) << "Broadcast ping finished for network" << addressEntry.broadcast().toString() + '/' + QString::number(addressEntry.prefixLength());
|
||||
// qCDebug(dcNetworkDetector()) << p->readAllStandardError();
|
||||
p->deleteLater();
|
||||
|
||||
if (m_runningPings.isEmpty()) {
|
||||
qCDebug(dcNetworkDetector()) << "All broadcast pings finished";
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef BROADCASTPING_H
|
||||
#define BROADCASTPING_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QProcess>
|
||||
#include <QNetworkAddressEntry>
|
||||
|
||||
class BroadcastPing : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BroadcastPing(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
public slots:
|
||||
void run();
|
||||
|
||||
private slots:
|
||||
void broadcastPingFinished(int exitCode);
|
||||
|
||||
private:
|
||||
QHash<QProcess*, QNetworkAddressEntry> m_runningPings;
|
||||
};
|
||||
|
||||
#endif // BROADCASTPING_H
|
||||
|
|
@ -62,7 +62,13 @@ void DeviceMonitor::arpLookupFinished(int exitCode)
|
|||
line.replace(QRegExp("[ ]{1,}"), " ");
|
||||
QStringList parts = line.split(" ");
|
||||
int lladdrIndex = parts.indexOf("lladdr");
|
||||
if (lladdrIndex >= 0 && parts.count() > lladdrIndex + 1 && parts.at(lladdrIndex+1).toLower() == m_macAddress.toLower()) {
|
||||
if (lladdrIndex == -1 || parts.count() <= lladdrIndex) {
|
||||
continue;
|
||||
}
|
||||
QString entryIP = parts.first();
|
||||
QString entryMAC = parts.at(lladdrIndex + 1);
|
||||
|
||||
if (entryMAC.toLower() == m_macAddress.toLower()) {
|
||||
found = true;
|
||||
QString entryIP = parts.first();
|
||||
if (parts.last() == "REACHABLE") {
|
||||
|
|
@ -72,13 +78,13 @@ void DeviceMonitor::arpLookupFinished(int exitCode)
|
|||
emit reachableChanged(true);
|
||||
}
|
||||
emit seen();
|
||||
m_lastSeenTime = QDateTime::currentDateTime();
|
||||
// Verify if IP address is still the same
|
||||
if (entryIP != mostRecentIP) {
|
||||
mostRecentIP = entryIP;
|
||||
}
|
||||
// If we have a reachable entry, stop processing here
|
||||
needsPing = false;
|
||||
m_failedPings = 0;
|
||||
break;
|
||||
} else {
|
||||
// ARP claims the device to be stale... Flagging device to require a ping.
|
||||
|
|
@ -94,6 +100,11 @@ void DeviceMonitor::arpLookupFinished(int exitCode)
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (entryIP == m_ipAddress) {
|
||||
warn("There seems to be a device with our IP but different MAC. Resetting IP config.");
|
||||
if (mostRecentIP == m_ipAddress) {
|
||||
mostRecentIP.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mostRecentIP != m_ipAddress) {
|
||||
|
|
@ -101,6 +112,14 @@ void DeviceMonitor::arpLookupFinished(int exitCode)
|
|||
m_ipAddress = mostRecentIP;
|
||||
emit addressChanged(mostRecentIP);
|
||||
}
|
||||
if (m_ipAddress.isEmpty()) {
|
||||
warn("Device not found in ARP cache and no IP config available. Marking as gone.");
|
||||
if (m_reachable) {
|
||||
m_reachable = false;
|
||||
emit reachableChanged(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!found) {
|
||||
log("Device not found in ARP cache.");
|
||||
arping();
|
||||
|
|
@ -144,13 +163,13 @@ void DeviceMonitor::arpingFinished(int exitCode)
|
|||
emit reachableChanged(true);
|
||||
}
|
||||
emit seen();
|
||||
m_failedPings = 0;
|
||||
m_lastSeenTime = QDateTime::currentDateTime();
|
||||
} else {
|
||||
log("ARP Ping failed.");
|
||||
ping();
|
||||
}
|
||||
// read data to discard it from socket
|
||||
QString data = QString::fromLatin1(m_pingProcess->readAll());
|
||||
QString data = QString::fromLatin1(m_arpingProcess->readAll());
|
||||
Q_UNUSED(data)
|
||||
// qCDebug(dcNetworkDetector()) << "have ping data" << data;
|
||||
}
|
||||
|
|
@ -172,16 +191,11 @@ void DeviceMonitor::pingFinished(int exitCode)
|
|||
emit reachableChanged(true);
|
||||
}
|
||||
emit seen();
|
||||
m_failedPings = 0;
|
||||
m_lastSeenTime = QDateTime::currentDateTime();
|
||||
} else {
|
||||
m_failedPings++;
|
||||
log("ICMP Ping failed for " + QString::number(m_failedPings) + " times. (Grace Period: " + QString::number(m_gracePeriod) + ")");
|
||||
if (m_failedPings > m_gracePeriod - 1) {
|
||||
// Regular ping fails too... Fire a broadcast ping in case the device has changed IP. After that, our ARP table should be up to date again.
|
||||
broadcastPing();
|
||||
}
|
||||
if (m_failedPings > m_gracePeriod && m_reachable) {
|
||||
log("Marking device as offline.");
|
||||
log("ICMP Ping failed.");
|
||||
if (m_reachable && m_lastSeenTime.addSecs(m_gracePeriod * 60) < QDateTime::currentDateTime()) {
|
||||
log("Exceeded grace period of " + QString::number(m_gracePeriod) + " minutes. Marking device as offline.");
|
||||
m_reachable = false;
|
||||
emit reachableChanged(false);
|
||||
}
|
||||
|
|
@ -192,41 +206,6 @@ void DeviceMonitor::pingFinished(int exitCode)
|
|||
// qCDebug(dcNetworkDetector()) << "have ping data" << data;
|
||||
}
|
||||
|
||||
void DeviceMonitor::broadcastPing()
|
||||
{
|
||||
QNetworkAddressEntry targetAddressEntry;
|
||||
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||
foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) {
|
||||
QHostAddress clientAddress(m_ipAddress);
|
||||
if (clientAddress.isInSubnet(addressEntry.ip(), addressEntry.prefixLength())) {
|
||||
targetAddressEntry = addressEntry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetAddressEntry.broadcast().isNull()) {
|
||||
warn("Could not find a suitable broadcast address Ping.");
|
||||
if (m_reachable) {
|
||||
m_reachable = false;
|
||||
emit reachableChanged(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QProcess *p = new QProcess(this);
|
||||
log("Sending Broadcast Ping on " + targetAddressEntry.ip().toString() + '/' + QString::number(targetAddressEntry.prefixLength()) + "...");
|
||||
p->start("fping", {"-a", "-c", "5", "-g", targetAddressEntry.broadcast().toString() + "/" + QString::number(targetAddressEntry.prefixLength())});
|
||||
connect(p, SIGNAL(finished(int)), this, SLOT(broadcastPingFinished(int)));
|
||||
}
|
||||
|
||||
void DeviceMonitor::broadcastPingFinished(int exitCode)
|
||||
{
|
||||
Q_UNUSED(exitCode);
|
||||
log("Broadcast ping finished");
|
||||
QProcess *p = static_cast<QProcess*>(sender());
|
||||
p->deleteLater();
|
||||
}
|
||||
|
||||
void DeviceMonitor::log(const QString &message)
|
||||
{
|
||||
qCDebug(dcNetworkDetector()).noquote().nospace() << m_name << " (" << m_macAddress << ", " << m_ipAddress << "): " << message;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QDateTime>
|
||||
|
||||
class DeviceMonitor : public QObject
|
||||
{
|
||||
|
|
@ -25,7 +26,6 @@ private:
|
|||
void lookupArpCache();
|
||||
void arping();
|
||||
void ping();
|
||||
void broadcastPing();
|
||||
|
||||
void log(const QString &message);
|
||||
void warn(const QString &message);
|
||||
|
|
@ -34,22 +34,19 @@ private slots:
|
|||
void arpLookupFinished(int exitCode);
|
||||
void arpingFinished(int exitCode);
|
||||
void pingFinished(int exitCode);
|
||||
void broadcastPingFinished(int exitCode);
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QString m_macAddress;
|
||||
QString m_ipAddress;
|
||||
QDateTime m_lastSeenTime;
|
||||
|
||||
bool m_reachable = false;
|
||||
|
||||
int m_gracePeriod = 5;
|
||||
|
||||
QProcess *m_arpLookupProcess = nullptr;
|
||||
QProcess *m_arpingProcess = nullptr;
|
||||
QProcess *m_pingProcess = nullptr;
|
||||
int m_failedPings = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif // DEVICEMONITOR_H
|
||||
|
|
|
|||
|
|
@ -57,12 +57,13 @@ DevicePluginNetworkDetector::DevicePluginNetworkDetector()
|
|||
{
|
||||
m_discovery = new Discovery(this);
|
||||
connect(m_discovery, &Discovery::finished, this, &DevicePluginNetworkDetector::discoveryFinished);
|
||||
|
||||
m_broadcastPing = new BroadcastPing(this);
|
||||
connect(m_broadcastPing, &BroadcastPing::finished, this, &DevicePluginNetworkDetector::broadcastPingFinished);
|
||||
}
|
||||
|
||||
DevicePluginNetworkDetector::~DevicePluginNetworkDetector()
|
||||
{
|
||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
||||
|
||||
if (m_discovery->isRunning()) {
|
||||
m_discovery->abort();
|
||||
}
|
||||
|
|
@ -70,8 +71,6 @@ DevicePluginNetworkDetector::~DevicePluginNetworkDetector()
|
|||
|
||||
void DevicePluginNetworkDetector::init()
|
||||
{
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginNetworkDetector::onPluginTimer);
|
||||
}
|
||||
|
||||
DeviceManager::DeviceSetupStatus DevicePluginNetworkDetector::setupDevice(Device *device)
|
||||
|
|
@ -86,7 +85,13 @@ DeviceManager::DeviceSetupStatus DevicePluginNetworkDetector::setupDevice(Device
|
|||
connect(monitor, &DeviceMonitor::addressChanged, this, &DevicePluginNetworkDetector::deviceAddressChanged);
|
||||
connect(monitor, &DeviceMonitor::seen, this, &DevicePluginNetworkDetector::deviceSeen);
|
||||
m_monitors.insert(monitor, device);
|
||||
monitor->update();
|
||||
|
||||
if (!m_pluginTimer) {
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(30);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, m_broadcastPing, &BroadcastPing::run);
|
||||
|
||||
m_broadcastPing->run();
|
||||
}
|
||||
|
||||
return DeviceManager::DeviceSetupStatusSuccess;
|
||||
}
|
||||
|
|
@ -114,9 +119,15 @@ void DevicePluginNetworkDetector::deviceRemoved(Device *device)
|
|||
DeviceMonitor *monitor = m_monitors.key(device);
|
||||
m_monitors.remove(monitor);
|
||||
delete monitor;
|
||||
|
||||
if (m_monitors.isEmpty()) {
|
||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
||||
m_pluginTimer = nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginNetworkDetector::onPluginTimer()
|
||||
void DevicePluginNetworkDetector::broadcastPingFinished()
|
||||
{
|
||||
foreach (DeviceMonitor *monitor, m_monitors.keys()) {
|
||||
monitor->update();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "discovery.h"
|
||||
#include "plugintimer.h"
|
||||
#include "devicemonitor.h"
|
||||
#include "broadcastping.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QXmlStreamReader>
|
||||
|
|
@ -59,11 +60,12 @@ private slots:
|
|||
void deviceAddressChanged(const QString &address);
|
||||
void deviceSeen();
|
||||
|
||||
void onPluginTimer();
|
||||
void broadcastPingFinished();
|
||||
|
||||
private:
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
Discovery *m_discovery = nullptr;
|
||||
BroadcastPing *m_broadcastPing = nullptr;
|
||||
QHash<DeviceMonitor*, Device*> m_monitors;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ SOURCES += \
|
|||
devicepluginnetworkdetector.cpp \
|
||||
host.cpp \
|
||||
discovery.cpp \
|
||||
devicemonitor.cpp
|
||||
devicemonitor.cpp \
|
||||
broadcastping.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginnetworkdetector.h \
|
||||
host.h \
|
||||
discovery.h \
|
||||
devicemonitor.h
|
||||
devicemonitor.h \
|
||||
broadcastping.h
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue