#include "devicemonitor.h" #include "extern-plugininfo.h" #include DeviceMonitor::DeviceMonitor(const QString &macAddress, const QString &ipAddress, QObject *parent): QObject(parent) { m_host = new Host(); m_host->setMacAddress(macAddress); m_host->setAddress(ipAddress); m_host->setReachable(false); m_arpLookupProcess = new QProcess(this); connect(m_arpLookupProcess, SIGNAL(finished(int)), this, SLOT(arpLookupFinished(int))); m_pingProcess = new QProcess(this); m_pingProcess->setReadChannelMode(QProcess::MergedChannels); connect(m_pingProcess, SIGNAL(finished(int)), this, SLOT(pingFinished(int))); } DeviceMonitor::~DeviceMonitor() { delete m_host; } void DeviceMonitor::update() { if (m_pingProcess->state() != QProcess::NotRunning) { qCDebug(dcNetworkDetector()) << "Previous ping still running for device" << m_host->address() << ". Not updating."; return; } lookupArpCache(); } void DeviceMonitor::lookupArpCache() { m_arpLookupProcess->start("ip", {"-4", "-s", "neighbor", "list"}); } void DeviceMonitor::ping() { qCDebug(dcNetworkDetector()) << "Sending ARP Ping to" << m_host->hostName() << m_host->macAddress() << 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) { if (exitCode != 0) { qCWarning(dcNetworkDetector()) << "Error looking up ARP cache."; return; } QString data = QString::fromLatin1(m_arpLookupProcess->readAll()); bool found = false; bool needsPing = true; foreach (QString line, data.split('\n')) { line.replace(QRegExp("[ ]{1,}"), " "); QStringList parts = line.split(" "); int lladdrIndex = parts.indexOf("lladdr"); if (lladdrIndex >= 0 && parts.count() > lladdrIndex && parts.at(lladdrIndex+1).toLower() == m_host->macAddress().toLower()) { found = true; if (parts.last() == "REACHABLE") { qCDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "found in ARP cache and claims to be REACHABLE"; if (!m_host->reachable()) { m_host->setReachable(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 { // 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(); } } } if (!found) { qCDebug(dcNetworkDetector()) << "Device" << m_host->macAddress() << "not found in ARP cache."; ping(); } else if (needsPing) { ping(); } } void DeviceMonitor::pingFinished(int exitCode) { if (exitCode == 0) { // we were able to ping the device qCDebug(dcNetworkDetector()) << "Ping successful for" << m_host->macAddress() << m_host->address(); m_host->seen(); if (!m_host->reachable()) { m_host->setReachable(true); emit reachableChanged(true); } emit seen(); } else { 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 QString data = QString::fromLatin1(m_pingProcess->readAll()); Q_UNUSED(data) // qCDebug(dcNetworkDetector()) << "have ping data" << data; }