Merge PR #70: Networkdetector: Implement the presencesensor interface

This commit is contained in:
Jenkins 2019-01-17 15:37:21 +01:00
commit f5a7005c37
5 changed files with 84 additions and 31 deletions

View File

@ -2,6 +2,8 @@
#include "extern-plugininfo.h" #include "extern-plugininfo.h"
#include <QNetworkInterface>
DeviceMonitor::DeviceMonitor(const QString &macAddress, const QString &ipAddress, QObject *parent): DeviceMonitor::DeviceMonitor(const QString &macAddress, const QString &ipAddress, QObject *parent):
QObject(parent) QObject(parent)
{ {
@ -25,6 +27,10 @@ DeviceMonitor::~DeviceMonitor()
void DeviceMonitor::update() void DeviceMonitor::update()
{ {
if (m_pingProcess->state() != QProcess::NotRunning) {
qCDebug(dcNetworkDetector()) << "Previous ping still running for device" << m_host->address() << ". Not updating.";
return;
}
lookupArpCache(); lookupArpCache();
} }
@ -35,54 +41,72 @@ void DeviceMonitor::lookupArpCache()
void DeviceMonitor::ping() void DeviceMonitor::ping()
{ {
// qCDebug(dcNetworkDetector()) << "Running:" << "ping" << "-c" << "1" << m_host->address(); qCDebug(dcNetworkDetector()) << "Sending ARP Ping to" << m_host->hostName() << m_host->macAddress() << m_host->address();
m_pingProcess->start("ping", {"-c", "1", m_host->address()}); QNetworkInterface targetInterface;
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) {
QHostAddress clientAddress(m_host->address());
if (clientAddress.isInSubnet(addressEntry.ip(), addressEntry.prefixLength())) {
targetInterface = interface;
break;
}
}
}
if (!targetInterface.isValid()) {
qCWarning(dcNetworkDetector()) << "Could not find a suitable interface to ping for" << m_host->address();
if (m_host->reachable()) {
m_host->setReachable(false);
emit reachableChanged(false);
}
return;
}
m_pingProcess->start("arping", {"-I", targetInterface.name(), "-f", "-w", "180", m_host->address()});
} }
void DeviceMonitor::arpLookupFinished(int exitCode) void DeviceMonitor::arpLookupFinished(int exitCode)
{ {
if (exitCode != 0) { if (exitCode != 0) {
qWarning(dcNetworkDetector()) << "Error looking up ARP cache."; qCWarning(dcNetworkDetector()) << "Error looking up ARP cache.";
return; return;
} }
QString data = QString::fromLatin1(m_arpLookupProcess->readAll()); QString data = QString::fromLatin1(m_arpLookupProcess->readAll());
bool found = false; bool found = false;
bool needsPing = true;
foreach (QString line, data.split('\n')) { foreach (QString line, data.split('\n')) {
line.replace(QRegExp("[ ]{1,}"), " "); line.replace(QRegExp("[ ]{1,}"), " ");
QStringList parts = line.split(" "); QStringList parts = line.split(" ");
int lladdrIndex = parts.indexOf("lladdr"); int lladdrIndex = parts.indexOf("lladdr");
if (lladdrIndex >= 0 && parts.count() > lladdrIndex && parts.at(lladdrIndex+1).toLower() == m_host->macAddress().toLower()) { if (lladdrIndex >= 0 && parts.count() > lladdrIndex && parts.at(lladdrIndex+1).toLower() == m_host->macAddress().toLower()) {
found = true; found = true;
// Verify if IP address is still the same
if (parts.first() != m_host->address()) {
m_host->setAddress(parts.first());
emit addressChanged(parts.first());
}
if (parts.last() == "REACHABLE") { if (parts.last() == "REACHABLE") {
qDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "found in ARP cache and claims to be REACHABLE"; qCDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "found in ARP cache and claims to be REACHABLE";
m_host->seen();
if (!m_host->reachable()) { if (!m_host->reachable()) {
m_host->setReachable(true); m_host->setReachable(true);
emit reachableChanged(true); emit reachableChanged(true);
} }
m_host->seen();
emit seen();
// Verify if IP address is still the same
if (parts.first() != m_host->address()) {
m_host->setAddress(parts.first());
emit addressChanged(parts.first());
}
// If we have a reachable entry, stop processing here
needsPing = false;
break;
} else { } else {
// ARP claims the device to be stale... try to ping it. // ARP claims the device to be stale... Flagging device to require a ping.
qCDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "found in ARP cache but is marked as" << parts.last() << ". Trying to ping it on" << m_host->address(); qCDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "found in ARP cache but is marked as" << parts.last();
ping();
} }
break;
} }
} }
if (!found) { if (!found) {
qCDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "not found in ARP cache. Trying to ping it on" << m_host->address(); qCDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "not found in ARP cache.";
ping();
} else if (needsPing) {
ping(); ping();
}
if (m_host->reachable() && m_host->lastSeenTime().addSecs(300) < QDateTime::currentDateTime()) {
qCDebug(dcNetworkDetector()) << "Could not reach device for > 5 mins. Marking it as gone." << m_host->address() << m_host->macAddress();
m_host->setReachable(false);
emit reachableChanged(false);
} }
} }
@ -90,13 +114,19 @@ void DeviceMonitor::pingFinished(int exitCode)
{ {
if (exitCode == 0) { if (exitCode == 0) {
// we were able to ping the device // we were able to ping the device
qCDebug(dcNetworkDetector()) << "Ping successful for" << m_host->macAddress() << m_host->address();
m_host->seen(); m_host->seen();
if (!m_host->reachable()) { if (!m_host->reachable()) {
m_host->setReachable(true); m_host->setReachable(true);
emit reachableChanged(true); emit reachableChanged(true);
} }
emit seen();
} else { } else {
qDebug(dcNetworkDetector()) << "Could not ping device" << m_host->macAddress() << m_host->address(); qCDebug(dcNetworkDetector()) << "Could not ping device" << m_host->macAddress() << m_host->address();
if (m_host->reachable()) {
m_host->setReachable(false);
emit reachableChanged(false);
}
} }
// read data to discard it from socket // read data to discard it from socket
QString data = QString::fromLatin1(m_pingProcess->readAll()); QString data = QString::fromLatin1(m_pingProcess->readAll());

View File

@ -19,6 +19,7 @@ public:
signals: signals:
void addressChanged(const QString &address); void addressChanged(const QString &address);
void reachableChanged(bool reachable); void reachableChanged(bool reachable);
void seen();
private: private:
void lookupArpCache(); void lookupArpCache();

View File

@ -80,7 +80,9 @@ DeviceManager::DeviceSetupStatus DevicePluginNetworkDetector::setupDevice(Device
DeviceMonitor *monitor = new DeviceMonitor(device->paramValue(networkDeviceDeviceMacAddressParamTypeId).toString(), device->paramValue(networkDeviceDeviceAddressParamTypeId).toString(), this); DeviceMonitor *monitor = new DeviceMonitor(device->paramValue(networkDeviceDeviceMacAddressParamTypeId).toString(), device->paramValue(networkDeviceDeviceAddressParamTypeId).toString(), this);
connect(monitor, &DeviceMonitor::reachableChanged, this, &DevicePluginNetworkDetector::deviceReachableChanged); connect(monitor, &DeviceMonitor::reachableChanged, this, &DevicePluginNetworkDetector::deviceReachableChanged);
connect(monitor, &DeviceMonitor::addressChanged, this, &DevicePluginNetworkDetector::deviceAddressChanged); connect(monitor, &DeviceMonitor::addressChanged, this, &DevicePluginNetworkDetector::deviceAddressChanged);
connect(monitor, &DeviceMonitor::seen, this, &DevicePluginNetworkDetector::deviceSeen);
m_monitors.insert(monitor, device); m_monitors.insert(monitor, device);
monitor->update();
return DeviceManager::DeviceSetupStatusSuccess; return DeviceManager::DeviceSetupStatusSuccess;
} }
@ -141,9 +143,9 @@ void DevicePluginNetworkDetector::deviceReachableChanged(bool reachable)
{ {
DeviceMonitor *monitor = static_cast<DeviceMonitor*>(sender()); DeviceMonitor *monitor = static_cast<DeviceMonitor*>(sender());
Device *device = m_monitors.value(monitor); Device *device = m_monitors.value(monitor);
if (device->stateValue(networkDeviceConnectedStateTypeId).toBool() != reachable) { if (device->stateValue(networkDeviceIsPresentStateTypeId).toBool() != reachable) {
qCDebug(dcNetworkDetector()) << "Device" << device->paramValue(networkDeviceDeviceMacAddressParamTypeId).toString() << "reachable changed" << reachable; qCDebug(dcNetworkDetector()) << "Device" << device->name() << device->paramValue(networkDeviceDeviceMacAddressParamTypeId).toString() << "reachable changed" << reachable;
device->setStateValue(networkDeviceConnectedStateTypeId, reachable); device->setStateValue(networkDeviceIsPresentStateTypeId, reachable);
} }
} }
@ -152,6 +154,17 @@ void DevicePluginNetworkDetector::deviceAddressChanged(const QString &address)
DeviceMonitor *monitor = static_cast<DeviceMonitor*>(sender()); DeviceMonitor *monitor = static_cast<DeviceMonitor*>(sender());
Device *device = m_monitors.value(monitor); Device *device = m_monitors.value(monitor);
if (device->paramValue(networkDeviceDeviceAddressParamTypeId).toString() != address) { if (device->paramValue(networkDeviceDeviceAddressParamTypeId).toString() != address) {
qCDebug(dcNetworkDetector()) << "Device" << device->name() << device->paramValue(networkDeviceDeviceMacAddressParamTypeId).toString() << "changed IP address to" << address;
device->setParamValue(networkDeviceDeviceAddressParamTypeId.toString(), address); device->setParamValue(networkDeviceDeviceAddressParamTypeId.toString(), address);
} }
} }
void DevicePluginNetworkDetector::deviceSeen()
{
DeviceMonitor *monitor = static_cast<DeviceMonitor*>(sender());
Device *device = m_monitors.value(monitor);
QDateTime oldLastSeen = QDateTime::fromTime_t(device->stateValue(networkDeviceLastSeenTimeStateTypeId).toInt());
if (oldLastSeen.addSecs(60) < QDateTime::currentDateTime()) {
device->setStateValue(networkDeviceLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t());
}
}

View File

@ -57,6 +57,7 @@ private slots:
void deviceReachableChanged(bool reachable); void deviceReachableChanged(bool reachable);
void deviceAddressChanged(const QString &address); void deviceAddressChanged(const QString &address);
void deviceSeen();
void onPluginTimer(); void onPluginTimer();

View File

@ -17,7 +17,7 @@
"Device", "Device",
"Sensor" "Sensor"
], ],
"interfaces": ["connectable"], "interfaces": [ "presencesensor" ],
"primaryStateTypeId": "cb43e1b5-4f61-4538-bfa2-c33055c542cf", "primaryStateTypeId": "cb43e1b5-4f61-4538-bfa2-c33055c542cf",
"createMethods": ["user", "discovery"], "createMethods": ["user", "discovery"],
"paramTypes": [ "paramTypes": [
@ -39,12 +39,20 @@
"stateTypes": [ "stateTypes": [
{ {
"id": "cb43e1b5-4f61-4538-bfa2-c33055c542cf", "id": "cb43e1b5-4f61-4538-bfa2-c33055c542cf",
"name": "connected", "name": "isPresent",
"displayName": "Device in network", "displayName": "Device is present",
"displayNameEvent": "Device in network changed", "displayNameEvent": "Device is present changed",
"type": "bool", "type": "bool",
"defaultValue": false, "defaultValue": false
"cached": false },
{
"id": "b51d54c9-cce1-43f0-a35d-52fc2d8d302c",
"name": "lastSeenTime",
"displayName": "Last seen time",
"displayNameEvent": "Last seen time changed",
"type": "int",
"unit": "UnixTime",
"defaultValue": 0
} }
] ]
} }