Restructure network discovery and add discovery

pull/511/head
Simon Stürz 2022-03-22 11:20:44 +01:00
parent bb03d17c79
commit 14ea1bef4a
27 changed files with 1388 additions and 330 deletions

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -41,6 +41,8 @@
NYMEA_LOGGING_CATEGORY(dcMacAddressDatabase, "MacAddressDatabase")
namespace nymeaserver {
MacAddressDatabase::MacAddressDatabase(QObject *parent) : QObject(parent)
{
// Find database in system data locations
@ -96,7 +98,7 @@ bool MacAddressDatabase::available() const
MacAddressDatabaseReply *MacAddressDatabase::lookupMacAddress(const QString &macAddress)
{
MacAddressDatabaseReply *reply = new MacAddressDatabaseReply(this);
MacAddressDatabaseReplyImpl *reply = new MacAddressDatabaseReplyImpl(this);
connect(reply, &MacAddressDatabaseReply::finished, reply, &MacAddressDatabaseReply::deleteLater);
reply->m_macAddress = macAddress;
@ -221,3 +223,4 @@ QString MacAddressDatabase::lookupMacAddressVendorInternal(const QString &macAdd
return manufacturer;
}
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -36,30 +36,11 @@
#include <QSqlDatabase>
#include <QFutureWatcher>
#include "libnymea.h"
#include "macaddressdatabasereplyimpl.h"
class LIBNYMEA_EXPORT MacAddressDatabaseReply : public QObject
{
Q_OBJECT
friend class MacAddressDatabase;
namespace nymeaserver {
public:
QString macAddress() const { return m_macAddress; };
QString manufacturer() const { return m_manufacturer; };
private:
explicit MacAddressDatabaseReply(QObject *parent = nullptr) : QObject(parent) { };
QString m_macAddress;
QString m_manufacturer;
qint64 m_startTimestamp;
signals:
void finished();
};
class LIBNYMEA_EXPORT MacAddressDatabase : public QObject
class MacAddressDatabase : public QObject
{
Q_OBJECT
public:
@ -77,9 +58,9 @@ private:
QString m_connectionName;
QString m_databaseName = "/usr/share/nymea/mac-addresses.db";
MacAddressDatabaseReply *m_currentReply = nullptr;
MacAddressDatabaseReplyImpl *m_currentReply = nullptr;
QFutureWatcher<QString> *m_futureWatcher = nullptr;
QQueue<MacAddressDatabaseReply *> m_pendingReplies;
QQueue<MacAddressDatabaseReplyImpl *> m_pendingReplies;
bool initDatabase();
void runNextLookup();
@ -90,4 +71,6 @@ private slots:
};
}
#endif // MACADDRESSDATABASE_H

View File

@ -0,0 +1,51 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "macaddressdatabasereplyimpl.h"
namespace nymeaserver {
MacAddressDatabaseReplyImpl::MacAddressDatabaseReplyImpl(QObject *parent) :
MacAddressDatabaseReply(parent)
{
}
QString MacAddressDatabaseReplyImpl::macAddress() const
{
return m_macAddress;
}
QString MacAddressDatabaseReplyImpl::manufacturer() const
{
return m_manufacturer;
}
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef MACADDRESSDATABASEREPLYIMPL_H
#define MACADDRESSDATABASEREPLYIMPL_H
#include <QObject>
#include <network/macaddressdatabasereply.h>
namespace nymeaserver {
class MacAddressDatabaseReplyImpl : public MacAddressDatabaseReply
{
Q_OBJECT
friend class MacAddressDatabase;
public:
explicit MacAddressDatabaseReplyImpl(QObject *parent = nullptr);
~MacAddressDatabaseReplyImpl() override = default;
QString macAddress() const override;
QString manufacturer() const override;
private:
QString m_macAddress;
QString m_manufacturer;
qint64 m_startTimestamp;
};
}
#endif // MACADDRESSDATABASEREPLYIMPL_H

View File

@ -0,0 +1,461 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkdevicediscoveryimpl.h"
#include "nymeasettings.h"
#include "loggingcategories.h"
#include <network/ping.h>
#include <network/arpsocket.h>
#include <network/networkutils.h>
#include <QDateTime>
NYMEA_LOGGING_CATEGORY(dcNetworkDeviceDiscovery, "NetworkDeviceDiscovery")
namespace nymeaserver {
NetworkDeviceDiscoveryImpl::NetworkDeviceDiscoveryImpl(QObject *parent) :
NetworkDeviceDiscovery(parent)
{
// Create ARP socket
m_arpSocket = new ArpSocket(this);
connect(m_arpSocket, &ArpSocket::arpResponse, this, &NetworkDeviceDiscoveryImpl::onArpResponseReceived);
bool arpAvailable = m_arpSocket->openSocket();
if (!arpAvailable) {
m_arpSocket->closeSocket();
}
// Create ping socket
m_ping = new Ping(this);
if (!m_ping->available())
qCWarning(dcNetworkDeviceDiscovery()) << "Failed to create ping tool" << m_ping->error();
// Init MAC database if available
m_macAddressDatabase = new MacAddressDatabase(this);
// Timer for max duration af a discovery
m_discoveryTimer = new QTimer(this);
m_discoveryTimer->setInterval(20000);
m_discoveryTimer->setSingleShot(true);
connect(m_discoveryTimer, &QTimer::timeout, this, [=](){
if (m_runningPingRepies.isEmpty() && m_currentReply) {
finishDiscovery();
}
});
// Timer for updating the monitors
m_monitorTimer = new QTimer(this);
m_monitorTimer->setInterval(5000);
m_monitorTimer->setSingleShot(false);
connect(m_monitorTimer, &QTimer::timeout, this, &NetworkDeviceDiscoveryImpl::evaluateMonitors);
if (!arpAvailable && !m_ping->available()) {
qCWarning(dcNetworkDeviceDiscovery()) << "Network device discovery is not available on this system.";
} else {
qCDebug(dcNetworkDeviceDiscovery()) << "Created successfully";
}
m_cacheSettings = new QSettings(NymeaSettings::cachePath() + "/network-device-discovery.cache", QSettings::IniFormat);
loadNetworkDeviceCache();
}
NetworkDeviceDiscoveryImpl::~NetworkDeviceDiscoveryImpl()
{
}
NetworkDeviceDiscoveryReply *NetworkDeviceDiscoveryImpl::discover()
{
if (m_currentReply) {
qCDebug(dcNetworkDeviceDiscovery()) << "Discovery already running. Returning current pending discovery reply...";
return m_currentReply;
}
qCDebug(dcNetworkDeviceDiscovery()) << "Starting network device discovery ...";
m_currentReply = new NetworkDeviceDiscoveryReplyImpl(this);
connect(m_currentReply, &NetworkDeviceDiscoveryReplyImpl::networkDeviceInfoAdded, this, &NetworkDeviceDiscoveryImpl::updateCache);
if (m_ping->available())
pingAllNetworkDevices();
if (m_arpSocket->isOpen())
m_arpSocket->sendRequest();
m_discoveryTimer->start();
m_running = true;
emit runningChanged(m_running);
return m_currentReply;
}
bool NetworkDeviceDiscoveryImpl::available() const
{
return m_arpSocket->isOpen() || m_ping->available();
}
bool NetworkDeviceDiscoveryImpl::enabled() const
{
return m_enabled;
}
bool NetworkDeviceDiscoveryImpl::running() const
{
return m_running;
}
NetworkDeviceMonitor *NetworkDeviceDiscoveryImpl::registerMonitor(const QString &macAddress)
{
if (m_monitors.contains(macAddress))
return m_monitors.value(macAddress);
NetworkDeviceInfo info;
if (m_networkInfoCache.contains(macAddress)) {
info = m_networkInfoCache.value(macAddress);
} else {
info.setMacAddress(macAddress);
qCDebug(dcNetworkDeviceDiscovery()) << "Adding mac address monitor for unresolved mac address. Starting a discovery...";
discover();
}
NetworkDeviceMonitorImpl *monitor = new NetworkDeviceMonitorImpl(info, this);
bool initRequired = m_monitors.isEmpty();
m_monitors.insert(macAddress, monitor);
if (initRequired) {
m_monitorTimer->start();
evaluateMonitors();
}
return monitor;
}
void NetworkDeviceDiscoveryImpl::unregisterMonitor(const QString &macAddress)
{
if (m_monitors.contains(macAddress)) {
NetworkDeviceMonitor *monitor = m_monitors.take(macAddress);
monitor->deleteLater();
}
}
void NetworkDeviceDiscoveryImpl::unregisterMonitor(NetworkDeviceMonitor *networkDeviceMonitor)
{
unregisterMonitor(networkDeviceMonitor->networkDeviceInfo().macAddress());
}
PingReply *NetworkDeviceDiscoveryImpl::ping(const QHostAddress &address)
{
// Note: we use any ping used trough this method also for the monitor evaluation
PingReply *reply = m_ping->ping(address);
connect(reply, &PingReply::finished, this, [=](){
foreach (NetworkDeviceMonitorImpl *monitor, m_monitors.values()) {
if (monitor->networkDeviceInfo().address() == address) {
processMonitorPingResult(reply, monitor);
}
}
});
return reply;
}
MacAddressDatabaseReply *NetworkDeviceDiscoveryImpl::lookupMacAddress(const QString &macAddress)
{
return m_macAddressDatabase->lookupMacAddress(macAddress);
}
bool NetworkDeviceDiscoveryImpl::sendArpRequest(const QHostAddress &address)
{
if (m_arpSocket && m_arpSocket->isOpen())
return m_arpSocket->sendRequest(address);
return false;
}
void NetworkDeviceDiscoveryImpl::setEnabled(bool enabled)
{
m_enabled = enabled;
emit enabledChanged(m_enabled);
// TODO: disable network discovery if false, not used for now
}
void NetworkDeviceDiscoveryImpl::pingAllNetworkDevices()
{
qCDebug(dcNetworkDeviceDiscovery()) << "Starting ping for all network devices...";
foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
if (networkInterface.flags().testFlag(QNetworkInterface::IsLoopBack))
continue;
if (!networkInterface.flags().testFlag(QNetworkInterface::IsUp))
continue;
if (!networkInterface.flags().testFlag(QNetworkInterface::IsRunning))
continue;
qCDebug(dcNetworkDeviceDiscovery()) << "Verifying network interface" << networkInterface.name() << networkInterface.hardwareAddress() << "...";
foreach (const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
qCDebug(dcNetworkDeviceDiscovery()) << " Checking entry" << entry.ip().toString();
// Only IPv4
if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol)
continue;
qCDebug(dcNetworkDeviceDiscovery()) << " Host address:" << entry.ip().toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Broadcast address:" << entry.broadcast().toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Netmask:" << entry.netmask().toString();
quint32 addressRangeStart = entry.ip().toIPv4Address() & entry.netmask().toIPv4Address();
quint32 addressRangeStop = entry.broadcast().toIPv4Address() | addressRangeStart;
quint32 range = addressRangeStop - addressRangeStart;
// Let's scan only 255.255.255.0 networks for now
if (range > 255)
continue;
qCDebug(dcNetworkDeviceDiscovery()) << " Address range" << range << " | from" << QHostAddress(addressRangeStart).toString() << "-->" << QHostAddress(addressRangeStop).toString();
// Send ping request to each address within the range
for (quint32 i = 1; i < range; i++) {
quint32 address = addressRangeStart + i;
QHostAddress targetAddress(address);
// Skip our self
if (targetAddress == entry.ip())
continue;
PingReply *reply = ping(targetAddress);
m_runningPingRepies.append(reply);
connect(reply, &PingReply::finished, this, [=](){
m_runningPingRepies.removeAll(reply);
if (reply->error() == PingReply::ErrorNoError) {
qCDebug(dcNetworkDeviceDiscovery()) << "Ping response from" << targetAddress.toString() << reply->hostName() << reply->duration() << "ms";
if (m_currentReply) {
m_currentReply->processPingResponse(targetAddress, reply->hostName());
}
}
if (m_runningPingRepies.isEmpty() && m_currentReply) {
qCWarning(dcNetworkDeviceDiscovery()) << "All ping replies finished for discovery." << m_currentReply->networkDeviceInfos().count();
finishDiscovery();
}
});
}
}
}
}
void NetworkDeviceDiscoveryImpl::finishDiscovery()
{
m_discoveryTimer->stop();
m_running = false;
emit runningChanged(m_running);
emit networkDeviceInfoCacheUpdated();
m_currentReply->processDiscoveryFinished();
m_currentReply->deleteLater();
m_currentReply = nullptr;
}
void NetworkDeviceDiscoveryImpl::processMonitorPingResult(PingReply *reply, NetworkDeviceMonitorImpl *monitor)
{
if (reply->error() == PingReply::ErrorNoError) {
qCDebug(dcNetworkDeviceDiscovery()) << "Ping response from" << monitor << reply->duration() << "ms";
monitor->setLastSeen(QDateTime::currentDateTime());
monitor->setReachable(true);
} else {
qCDebug(dcNetworkDeviceDiscovery()) << "Failed to ping device from" << monitor << reply->error();
monitor->setReachable(false);
}
}
void NetworkDeviceDiscoveryImpl::loadNetworkDeviceCache()
{
qCDebug(dcNetworkDeviceDiscovery()) << "Loading cached network device information from" << m_cacheSettings->fileName();
m_networkInfoCache.clear();
m_cacheSettings->beginGroup("NetworkDeviceInfos");
foreach (const QString &macAddress, m_cacheSettings->childGroups()) {
m_cacheSettings->beginGroup(macAddress);
NetworkDeviceInfo info(macAddress);
info.setAddress(QHostAddress(m_cacheSettings->value("address").toString()));
info.setHostName(m_cacheSettings->value("hostName").toString());
info.setMacAddressManufacturer(m_cacheSettings->value("manufacturer").toString());
info.setNetworkInterface(QNetworkInterface::interfaceFromName(m_cacheSettings->value("interface").toString()));
if (info.isValid() && info.isComplete()) {
qCDebug(dcNetworkDeviceDiscovery()) << "Loaded cached" << info;
m_networkInfoCache.insert(info.macAddress(), info);
} else {
qCWarning(dcNetworkDeviceDiscovery()) << "Clean up invalid cached network device info from cache" << info;
m_cacheSettings->remove("");
}
m_cacheSettings->endGroup(); // mac address
}
m_cacheSettings->endGroup(); // NetworkDeviceInfos
}
void NetworkDeviceDiscoveryImpl::removeFromNetworkDeviceCache(const QString &macAddress)
{
if (macAddress.isEmpty())
return;
m_networkInfoCache.remove(macAddress);
m_cacheSettings->beginGroup("NetworkDeviceInfos");
m_cacheSettings->beginGroup(macAddress);
m_cacheSettings->remove("");
m_cacheSettings->endGroup(); // mac address
m_cacheSettings->endGroup(); // NetworkDeviceInfos
}
void NetworkDeviceDiscoveryImpl::saveNetworkDeviceCache(const NetworkDeviceInfo &deviceInfo)
{
m_cacheSettings->beginGroup("NetworkDeviceInfos");
m_cacheSettings->beginGroup(deviceInfo.macAddress());
m_cacheSettings->setValue("address", deviceInfo.address().toString());
m_cacheSettings->setValue("hostName", deviceInfo.hostName());
m_cacheSettings->setValue("manufacturer", deviceInfo.macAddressManufacturer());
m_cacheSettings->setValue("interface", deviceInfo.networkInterface().name());
m_cacheSettings->endGroup(); // mac address
m_cacheSettings->endGroup(); // NetworkDeviceInfos
}
void NetworkDeviceDiscoveryImpl::updateCache(const NetworkDeviceInfo &deviceInfo)
{
if (deviceInfo.macAddress().isEmpty())
return;
if (m_monitors.contains(deviceInfo.macAddress())) {
NetworkDeviceMonitorImpl *monitor = m_monitors.value(deviceInfo.macAddress());
monitor->updateNetworkDeviceInfo(deviceInfo);
}
if (m_networkInfoCache.value(deviceInfo.macAddress()) == deviceInfo)
return;
m_networkInfoCache[deviceInfo.macAddress()] = deviceInfo;
saveNetworkDeviceCache(deviceInfo);
}
void NetworkDeviceDiscoveryImpl::onArpResponseReceived(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress)
{
// Ignore ARP from zero mac
if (macAddress == QString("00:00:00:00:00:00")) {
qCDebug(dcNetworkDeviceDiscovery()) << "Ignoring ARP reply from" << address.toString() << macAddress << interface.name();
return;
}
qCDebug(dcNetworkDeviceDiscovery()) << "ARP reply received" << address.toString() << macAddress << interface.name();
if (m_networkInfoCache.contains(macAddress)) {
if (m_networkInfoCache.value(macAddress).address() != address) {
m_networkInfoCache[macAddress].setAddress(address);
saveNetworkDeviceCache(m_networkInfoCache[macAddress]);
}
}
// Update the monitors
foreach (NetworkDeviceMonitorImpl *monitor, m_monitors) {
if (monitor->networkDeviceInfo().macAddress() == macAddress) {
monitor->setLastSeen(QDateTime::currentDateTime());
monitor->setReachable(true);
if (monitor->networkDeviceInfo().address() != address) {
monitor->m_networkDeviceInfo.setAddress(address);
emit monitor->networkDeviceInfoChanged(monitor->networkDeviceInfo());
}
}
}
// Check if we have a reply running
if (m_currentReply) {
// First process the response
m_currentReply->processArpResponse(interface, address, macAddress);
// Check if we know the mac address manufacturer from the cache
if (m_networkInfoCache.contains(macAddress)) {
QString cachedManufacturer = m_networkInfoCache[macAddress].macAddressManufacturer();
if (!cachedManufacturer.isEmpty()) {
// Found the mac address manufacturer in the cache, let's use that
m_currentReply->processMacManufacturer(macAddress, cachedManufacturer);
}
} else {
// Lookup the mac address vendor if possible
if (m_macAddressDatabase->available()) {
MacAddressDatabaseReply *reply = m_macAddressDatabase->lookupMacAddress(macAddress);
connect(reply, &MacAddressDatabaseReply::finished, m_currentReply, [=](){
qCDebug(dcNetworkDeviceDiscovery()) << "MAC manufacturer lookup finished for" << macAddress << ":" << reply->manufacturer();
m_currentReply->processMacManufacturer(macAddress, reply->manufacturer());
});
} else {
// Note: set the mac manufacturer explicitly to make the info complete
m_currentReply->processMacManufacturer(macAddress, QString());
}
}
}
}
void NetworkDeviceDiscoveryImpl::evaluateMonitors()
{
foreach (NetworkDeviceMonitorImpl *monitor, m_monitors) {
// Start action if we have not seen the device for gracePeriod seconds
const int gracePeriod = 60;
QDateTime currentDateTime = QDateTime::currentDateTime();
bool requiresRefresh = false;
if (monitor->lastSeen().isNull()) {
qCDebug(dcNetworkDeviceDiscovery()) << monitor << "requires refresh. Not seen yet";
requiresRefresh = true;
}
if (!requiresRefresh && currentDateTime > monitor->lastSeen().addSecs(gracePeriod)) {
qCDebug(dcNetworkDeviceDiscovery()) << monitor << "requires refresh. Not see since" << (currentDateTime.toMSecsSinceEpoch() - monitor->lastSeen().toMSecsSinceEpoch()) / 1000.0 << "s";
requiresRefresh = true;
}
if (!requiresRefresh)
continue;
if (monitor->networkDeviceInfo().address().isNull()) {
// Not known yet
// TODO: load from cache
continue;
}
// Try to ping first
qCDebug(dcNetworkDeviceDiscovery()) << monitor << "try to ping" << monitor->networkDeviceInfo().address().toString();
PingReply *reply = m_ping->ping(monitor->networkDeviceInfo().address());
connect(reply, &PingReply::finished, monitor, [=](){
processMonitorPingResult(reply, monitor);
});
}
}
}

View File

@ -0,0 +1,117 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef NETWORKDEVICEDISCOVERYIMPL_H
#define NETWORKDEVICEDISCOVERYIMPL_H
#include <QObject>
#include <QSettings>
#include <QLoggingCategory>
#include <network/networkdeviceinfo.h>
#include <network/networkdevicediscovery.h>
#include "macaddressdatabase.h"
#include "networkdevicemonitorimpl.h"
#include "macaddressdatabasereplyimpl.h"
#include "networkdevicediscoveryreplyimpl.h"
class Ping;
class ArpSocket;
Q_DECLARE_LOGGING_CATEGORY(dcNetworkDeviceDiscovery)
namespace nymeaserver {
class NetworkDeviceDiscoveryImpl : public NetworkDeviceDiscovery
{
Q_OBJECT
public:
explicit NetworkDeviceDiscoveryImpl(QObject *parent = nullptr);
~NetworkDeviceDiscoveryImpl() override;
bool available() const override;
bool enabled() const override;
bool running() const override;
NetworkDeviceDiscoveryReply *discover() override;
NetworkDeviceMonitor *registerMonitor(const QString &macAddress) override;
void unregisterMonitor(const QString &macAddress) override;
void unregisterMonitor(NetworkDeviceMonitor *networkDeviceMonitor) override;
PingReply *ping(const QHostAddress &address) override;
MacAddressDatabaseReply *lookupMacAddress(const QString &macAddress) override;
bool sendArpRequest(const QHostAddress &address) override;
protected:
void setEnabled(bool enabled) override;
private:
MacAddressDatabase *m_macAddressDatabase = nullptr;
ArpSocket *m_arpSocket = nullptr;
Ping *m_ping = nullptr;
bool m_enabled = true;
bool m_running = false;
QTimer *m_discoveryTimer = nullptr;
QTimer *m_monitorTimer = nullptr;
NetworkDeviceDiscoveryReplyImpl *m_currentReply = nullptr;
QList<PingReply *> m_runningPingRepies;
QHash<QString, NetworkDeviceMonitorImpl *> m_monitors;
QSettings *m_cacheSettings;
QHash<QString, NetworkDeviceInfo> m_networkInfoCache;
void pingAllNetworkDevices();
void finishDiscovery();
void processMonitorPingResult(PingReply *reply, NetworkDeviceMonitorImpl *monitor);
void loadNetworkDeviceCache();
void removeFromNetworkDeviceCache(const QString &macAddress);
void saveNetworkDeviceCache(const NetworkDeviceInfo &deviceInfo);
void updateCache(const NetworkDeviceInfo &deviceInfo);
private slots:
void onArpResponseReceived(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress);
void evaluateMonitors();
};
}
#endif // NETWORKDEVICEDISCOVERYIMPL_H

View File

@ -0,0 +1,174 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkdevicediscoveryreplyimpl.h"
#include "loggingcategories.h"
#include <QDateTime>
namespace nymeaserver {
NYMEA_LOGGING_CATEGORY(dcNetworkDeviceDiscovery, "NetworkDeviceDiscovery")
NetworkDeviceDiscoveryReplyImpl::NetworkDeviceDiscoveryReplyImpl(QObject *parent) :
NetworkDeviceDiscoveryReply(parent)
{
m_startTimestamp = QDateTime::currentMSecsSinceEpoch();
}
NetworkDeviceInfos NetworkDeviceDiscoveryReplyImpl::networkDeviceInfos() const
{
return m_networkDeviceInfos;
}
NetworkDeviceInfos NetworkDeviceDiscoveryReplyImpl::virtualNetworkDeviceInfos() const
{
return m_virtualNetworkDeviceInfos;
}
QString NetworkDeviceDiscoveryReplyImpl::macAddressFromHostAddress(const QHostAddress &address)
{
foreach (const NetworkDeviceInfo &info, m_networkDeviceCache) {
if (info.address() == address) {
return info.macAddress();
}
}
return QString();
}
bool NetworkDeviceDiscoveryReplyImpl::hasHostAddress(const QHostAddress &address)
{
return ! macAddressFromHostAddress(address).isEmpty();
}
void NetworkDeviceDiscoveryReplyImpl::processPingResponse(const QHostAddress &address, const QString &hostName)
{
foreach (const NetworkDeviceInfo &info, m_networkDeviceCache) {
if (info.address() == address) {
// Already found info, set host name and check if complete
m_networkDeviceCache[info.macAddress()].setHostName(hostName);
if (m_networkDeviceCache[info.macAddress()].isComplete() && m_networkDeviceCache[info.macAddress()].isValid()) {
emit networkDeviceInfoAdded(m_networkDeviceCache[info.macAddress()]);
m_networkDeviceInfos.append(m_networkDeviceCache.take(info.macAddress()));
}
emit hostAddressDiscovered(address);
return;
}
}
// Not added yet
NetworkDeviceInfo info;
info.setAddress(address);
info.setHostName(hostName);
m_pingCache.insert(address, info);
emit hostAddressDiscovered(address);
}
void NetworkDeviceDiscoveryReplyImpl::processArpResponse(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress)
{
if (m_pingCache.contains(address)) {
NetworkDeviceInfo info = m_pingCache.take(address);
info.setAddress(address);
info.setNetworkInterface(interface);
info.setMacAddress(macAddress);
m_networkDeviceCache[macAddress] = info;
} else {
if (m_networkDeviceCache.contains(macAddress)) {
m_networkDeviceCache[macAddress].setNetworkInterface(interface);
m_networkDeviceCache[macAddress].setAddress(address);
} else {
NetworkDeviceInfo info = m_pingCache.take(address);
info.setNetworkInterface(interface);
info.setMacAddress(macAddress);
m_networkDeviceCache[macAddress] = info;
}
}
if (m_networkDeviceCache[macAddress].isComplete() && m_networkDeviceCache[macAddress].isValid()) {
m_networkDeviceInfos.append(m_networkDeviceCache.take(macAddress));
emit networkDeviceInfoAdded(m_networkDeviceCache[macAddress]);
}
}
void NetworkDeviceDiscoveryReplyImpl::processMacManufacturer(const QString &macAddress, const QString &manufacturer)
{
if (m_networkDeviceCache.contains(macAddress)) {
m_networkDeviceCache[macAddress].setMacAddressManufacturer(manufacturer);
} else {
NetworkDeviceInfo info(macAddress);
info.setMacAddressManufacturer(manufacturer);
m_networkDeviceCache[macAddress] = info;
}
if (m_networkDeviceCache[macAddress].isComplete() && m_networkDeviceCache[macAddress].isValid()) {
m_networkDeviceInfos.append(m_networkDeviceCache.take(macAddress));
emit networkDeviceInfoAdded(m_networkDeviceCache[macAddress]);
}
}
void NetworkDeviceDiscoveryReplyImpl::processDiscoveryFinished()
{
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startTimestamp;
qCDebug(dcNetworkDeviceDiscovery()) << "Discovery finished. Found" << networkDeviceInfos().count() << "network devices in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
// Process what's left and add it to result list
foreach (const NetworkDeviceInfo &info, m_networkDeviceInfos) {
qCDebug(dcNetworkDeviceDiscovery()) << "--> " << info;
}
// Create valid infos from the ping cache and offer them in the virtual infos
foreach (const NetworkDeviceInfo &info, m_pingCache) {
NetworkDeviceInfo finalInfo = info;
finalInfo.setAddress(finalInfo.address());
finalInfo.setHostName(finalInfo.hostName());
finalInfo.setMacAddress(finalInfo.macAddress());
finalInfo.setNetworkInterface(finalInfo.networkInterface());
finalInfo.setMacAddressManufacturer(finalInfo.macAddressManufacturer());
m_virtualNetworkDeviceInfos.append(info);
}
m_virtualNetworkDeviceInfos.sortNetworkDevices();
qCDebug(dcNetworkDeviceDiscovery()) << "Virtual hosts (" << m_virtualNetworkDeviceInfos.count() << ")";
foreach (const NetworkDeviceInfo &info, m_virtualNetworkDeviceInfos) {
qCDebug(dcNetworkDeviceDiscovery()) << "--> " << info;
}
qCDebug(dcNetworkDeviceDiscovery()) << "Rest:";
foreach (const NetworkDeviceInfo &info, m_networkDeviceCache) {
qCDebug(dcNetworkDeviceDiscovery()) << "--> " << info << "Complete:" << info.isComplete() << "Valid:" << info.isValid();
}
emit finished();
}
}

View File

@ -0,0 +1,77 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef NETWORKDEVICEDISCOVERYREPLYIMPL_H
#define NETWORKDEVICEDISCOVERYREPLYIMPL_H
#include <QHash>
#include <QObject>
#include "network/networkdeviceinfo.h"
#include "network/networkdevicediscoveryreply.h"
namespace nymeaserver {
class NetworkDeviceDiscoveryReplyImpl : public NetworkDeviceDiscoveryReply
{
Q_OBJECT
friend class NetworkDeviceDiscoveryImpl;
public:
explicit NetworkDeviceDiscoveryReplyImpl(QObject *parent = nullptr);
~NetworkDeviceDiscoveryReplyImpl() override = default;
NetworkDeviceInfos networkDeviceInfos() const override;
NetworkDeviceInfos virtualNetworkDeviceInfos() const override;
private:
NetworkDeviceInfos m_networkDeviceInfos; // Contains only complete and valid infos
NetworkDeviceInfos m_virtualNetworkDeviceInfos; // Contains ping responses without ARP, like VPN devices
QHash<QString, NetworkDeviceInfo> m_networkDeviceCache;
qint64 m_startTimestamp;
// Temporary cache for ping responses where the mac is not known yet (like VPN devices)
QHash<QHostAddress, NetworkDeviceInfo> m_pingCache;
QString macAddressFromHostAddress(const QHostAddress &address);
bool hasHostAddress(const QHostAddress &address);
// Add or update the network device info and verify if completed
void processPingResponse(const QHostAddress &address, const QString &hostName);
void processArpResponse(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress);
void processMacManufacturer(const QString &macAddress, const QString &manufacturer);
void processDiscoveryFinished();
};
}
#endif // NETWORKDEVICEDISCOVERYREPLYIMPL_H

View File

@ -0,0 +1,89 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkdevicemonitorimpl.h"
namespace nymeaserver {
NetworkDeviceMonitorImpl::NetworkDeviceMonitorImpl(const NetworkDeviceInfo &networkDeviceInfo, QObject *parent) :
NetworkDeviceMonitor(parent),
m_networkDeviceInfo(networkDeviceInfo)
{
}
NetworkDeviceMonitorImpl::~NetworkDeviceMonitorImpl()
{
}
NetworkDeviceInfo NetworkDeviceMonitorImpl::networkDeviceInfo() const
{
return m_networkDeviceInfo;
}
bool NetworkDeviceMonitorImpl::reachable() const
{
return m_reachable;
}
void NetworkDeviceMonitorImpl::setReachable(bool reachable)
{
if (m_reachable == reachable)
return;
m_reachable = reachable;
emit reachableChanged(m_reachable);
}
QDateTime NetworkDeviceMonitorImpl::lastSeen() const
{
return m_lastSeen;
}
void NetworkDeviceMonitorImpl::setLastSeen(const QDateTime lastSeen)
{
if (m_lastSeen == lastSeen)
return;
m_lastSeen = lastSeen;
emit lastSeenChanged(m_lastSeen);
}
void NetworkDeviceMonitorImpl::updateNetworkDeviceInfo(const NetworkDeviceInfo &networkDeviceInfo)
{
if (m_networkDeviceInfo == networkDeviceInfo)
return;
m_networkDeviceInfo = networkDeviceInfo;
emit networkDeviceInfoChanged(m_networkDeviceInfo);
}
}

View File

@ -0,0 +1,70 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef NETWORKDEVICEMONITORIMPL_H
#define NETWORKDEVICEMONITORIMPL_H
#include <QObject>
#include <QDateTime>
#include "network/networkdevicemonitor.h"
namespace nymeaserver {
class NetworkDeviceMonitorImpl : public NetworkDeviceMonitor
{
Q_OBJECT
friend class NetworkDeviceDiscoveryImpl;
public:
explicit NetworkDeviceMonitorImpl(const NetworkDeviceInfo &networkDeviceInfo, QObject *parent = nullptr);
~NetworkDeviceMonitorImpl();
NetworkDeviceInfo networkDeviceInfo() const override;
bool reachable() const override;
void setReachable(bool reachable);
QDateTime lastSeen() const override;
void setLastSeen(const QDateTime lastSeen);
private:
NetworkDeviceInfo m_networkDeviceInfo;
bool m_reachable = false;
QDateTime m_lastSeen;
void updateNetworkDeviceInfo(const NetworkDeviceInfo &networkDeviceInfo);
};
}
#endif // NETWORKDEVICEMONITORIMPL_H

View File

@ -46,7 +46,7 @@
#include "hardware/modbus/modbusrtumanager.h"
#include "hardware/modbus/modbusrtuhardwareresourceimplementation.h"
#include "network/networkdevicediscovery.h"
#include "hardware/network/networkdevicediscoveryimpl.h"
namespace nymeaserver {
@ -79,7 +79,7 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform,
m_modbusRtuResource = new ModbusRtuHardwareResourceImplementation(modbusRtuManager, this);
m_networkDeviceDiscovery = new NetworkDeviceDiscovery(this);
m_networkDeviceDiscovery = new NetworkDeviceDiscoveryImpl(this);
// Enable all the resources
setResourceEnabled(m_pluginTimerManager, true);

View File

@ -45,6 +45,7 @@ class ZigbeeManager;
class ZigbeeHardwareResourceImplementation;
class ModbusRtuManager;
class ModbusRtuHardwareResourceImplementation;
class NetworkDeviceDiscoveryImpl;
class HardwareManagerImplementation : public HardwareManager
{
@ -84,7 +85,7 @@ private:
I2CManager *m_i2cManager = nullptr;
ZigbeeHardwareResourceImplementation *m_zigbeeResource = nullptr;
ModbusRtuHardwareResourceImplementation *m_modbusRtuResource = nullptr;
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
NetworkDeviceDiscoveryImpl *m_networkDeviceDiscovery = nullptr;
};

View File

@ -61,6 +61,7 @@ RESOURCES += $$top_srcdir/icons.qrc \
HEADERS += nymeacore.h \
hardware/network/macaddressdatabasereplyimpl.h \
hardware/serialport/serialportmonitor.h \
integrations/apikeysprovidersloader.h \
integrations/plugininfocache.h \
@ -141,7 +142,11 @@ HEADERS += nymeacore.h \
hardware/modbus/modbusrtumanager.h \
hardware/modbus/modbusrtumasterimpl.h \
hardware/modbus/modbusrtureplyimpl.h \
hardware/network/macaddressdatabase.h \
hardware/network/networkaccessmanagerimpl.h \
hardware/network/networkdevicediscoveryimpl.h \
hardware/network/networkdevicediscoveryreplyimpl.h \
hardware/network/networkdevicemonitorimpl.h \
hardware/network/upnp/upnpdiscoveryimplementation.h \
hardware/network/upnp/upnpdiscoveryrequest.h \
hardware/network/upnp/upnpdiscoveryreplyimplementation.h \
@ -161,6 +166,7 @@ HEADERS += nymeacore.h \
SOURCES += nymeacore.cpp \
hardware/network/macaddressdatabasereplyimpl.cpp \
hardware/serialport/serialportmonitor.cpp \
integrations/apikeysprovidersloader.cpp \
integrations/plugininfocache.cpp \
@ -233,7 +239,11 @@ SOURCES += nymeacore.cpp \
hardware/modbus/modbusrtumanager.cpp \
hardware/modbus/modbusrtumasterimpl.cpp \
hardware/modbus/modbusrtureplyimpl.cpp \
hardware/network/macaddressdatabase.cpp \
hardware/network/networkaccessmanagerimpl.cpp \
hardware/network/networkdevicediscoveryimpl.cpp \
hardware/network/networkdevicediscoveryreplyimpl.cpp \
hardware/network/networkdevicemonitorimpl.cpp \
hardware/network/upnp/upnpdiscoveryimplementation.cpp \
hardware/network/upnp/upnpdiscoveryrequest.cpp \
hardware/network/upnp/upnpdiscoveryreplyimplementation.cpp \

View File

@ -44,11 +44,12 @@ HEADERS += \
network/apikeys/apikeysprovider.h \
network/apikeys/apikeystorage.h \
network/arpsocket.h \
network/macaddressdatabase.h \
network/macaddressdatabasereply.h \
network/networkdevicediscovery.h \
network/networkdevicediscoveryreply.h \
network/networkdeviceinfo.h \
network/networkdeviceinfos.h \
network/networkdevicemonitor.h \
network/networkutils.h \
network/ping.h \
network/pingreply.h \
@ -149,11 +150,11 @@ SOURCES += \
network/apikeys/apikeysprovider.cpp \
network/apikeys/apikeystorage.cpp \
network/arpsocket.cpp \
network/macaddressdatabase.cpp \
network/macaddressdatabasereply.cpp \
network/networkdevicediscovery.cpp \
network/networkdevicediscoveryreply.cpp \
network/networkdeviceinfo.cpp \
network/networkdeviceinfos.cpp \
network/networkdevicemonitor.cpp \
network/networkutils.cpp \
network/ping.cpp \
network/pingreply.cpp \

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -28,15 +28,9 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkdevicediscoveryreply.h"
#include "macaddressdatabasereply.h"
NetworkDeviceDiscoveryReply::NetworkDeviceDiscoveryReply(QObject *parent) :
QObject(parent)
MacAddressDatabaseReply::MacAddressDatabaseReply(QObject *parent) : QObject(parent)
{
}
NetworkDeviceInfos &NetworkDeviceDiscoveryReply::networkDeviceInfos()
{
return m_networkDeviceInfos;
}

View File

@ -0,0 +1,54 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef MACADDRESSDATABASEREPLY_H
#define MACADDRESSDATABASEREPLY_H
#include <QObject>
#include "libnymea.h"
class LIBNYMEA_EXPORT MacAddressDatabaseReply : public QObject
{
Q_OBJECT
public:
explicit MacAddressDatabaseReply(QObject *parent = nullptr);
virtual ~MacAddressDatabaseReply() = default;
virtual QString macAddress() const = 0;
virtual QString manufacturer() const = 0;
signals:
void finished();
};
#endif // MACADDRESSDATABASEREPLY_H

View File

@ -42,7 +42,7 @@
#include <QDebug>
#include <QUrl>
class LIBNYMEA_EXPORT NetworkAccessManager : public HardwareResource
class LIBNYMEA_EXPORT NetworkAccessManager : public HardwareResource
{
Q_OBJECT

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -29,242 +29,10 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkdevicediscovery.h"
#include "loggingcategories.h"
#include "networkutils.h"
#include "macaddressdatabase.h"
#include "arpsocket.h"
#include <QDateTime>
NYMEA_LOGGING_CATEGORY(dcNetworkDeviceDiscovery, "NetworkDeviceDiscovery")
NetworkDeviceDiscovery::NetworkDeviceDiscovery(QObject *parent) :
QObject(parent)
HardwareResource("Network device discovery", parent)
{
// Create ARP socket
m_arpSocket = new ArpSocket(this);
connect(m_arpSocket, &ArpSocket::arpResponse, this, &NetworkDeviceDiscovery::onArpResponseRceived);
bool arpAvailable = m_arpSocket->openSocket();
if (!arpAvailable) {
m_arpSocket->closeSocket();
}
// Create ping socket
m_ping = new Ping(this);
if (!m_ping->available())
qCWarning(dcNetworkDeviceDiscovery()) << "Failed to create ping tool" << m_ping->error();
// Init MAC database if available
m_macAddressDatabase = new MacAddressDatabase(this);
// Timer for max duration af a discovery
m_discoveryTimer = new QTimer(this);
m_discoveryTimer->setInterval(20000);
m_discoveryTimer->setSingleShot(true);
connect(m_discoveryTimer, &QTimer::timeout, this, [=](){
if (m_runningPingRepies.isEmpty() && m_currentReply) {
finishDiscovery();
}
});
if (!arpAvailable && !m_ping->available()) {
qCWarning(dcNetworkDeviceDiscovery()) << "Network device discovery is not available on this system.";
} else {
qCDebug(dcNetworkDeviceDiscovery()) << "Created successfully";
}
}
NetworkDeviceDiscoveryReply *NetworkDeviceDiscovery::discover()
{
if (m_currentReply) {
qCDebug(dcNetworkDeviceDiscovery()) << "Discovery already running. Returning current pending discovery reply...";
return m_currentReply;
}
qCDebug(dcNetworkDeviceDiscovery()) << "Starting network device discovery ...";
NetworkDeviceDiscoveryReply *reply = new NetworkDeviceDiscoveryReply(this);
m_currentReply = reply;
m_currentReply->m_startTimestamp = QDateTime::currentMSecsSinceEpoch();
if (m_ping->available()) {
pingAllNetworkDevices();
}
if (m_arpSocket->isOpen()) {
m_arpSocket->sendRequest();
}
m_discoveryTimer->start();
m_running = true;
emit runningChanged(m_running);
return reply;
}
bool NetworkDeviceDiscovery::available() const
{
return m_arpSocket->isOpen() || m_ping->available();
}
bool NetworkDeviceDiscovery::running() const
{
return m_running;
}
PingReply *NetworkDeviceDiscovery::ping(const QHostAddress &address)
{
return m_ping->ping(address);
}
MacAddressDatabaseReply *NetworkDeviceDiscovery::lookupMacAddress(const QString &macAddress)
{
return m_macAddressDatabase->lookupMacAddress(macAddress);
}
void NetworkDeviceDiscovery::pingAllNetworkDevices()
{
qCDebug(dcNetworkDeviceDiscovery()) << "Starting ping for all network devices...";
foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
if (networkInterface.flags().testFlag(QNetworkInterface::IsLoopBack))
continue;
if (!networkInterface.flags().testFlag(QNetworkInterface::IsUp))
continue;
if (!networkInterface.flags().testFlag(QNetworkInterface::IsRunning))
continue;
qCDebug(dcNetworkDeviceDiscovery()) << "Verifying network interface" << networkInterface.name() << networkInterface.hardwareAddress() << "...";
foreach (const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
// Only IPv4
if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol)
continue;
qCDebug(dcNetworkDeviceDiscovery()) << " Host address:" << entry.ip().toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Broadcast address:" << entry.broadcast().toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Netmask:" << entry.netmask().toString();
quint32 addressRangeStart = entry.ip().toIPv4Address() & entry.netmask().toIPv4Address();
quint32 addressRangeStop = entry.broadcast().toIPv4Address() | addressRangeStart;
quint32 range = addressRangeStop - addressRangeStart;
// Let's scan only 255.255.255.0 networks for now
if (range > 255)
continue;
qCDebug(dcNetworkDeviceDiscovery()) << " Address range" << range << " | from" << QHostAddress(addressRangeStart).toString() << "-->" << QHostAddress(addressRangeStop).toString();
// Send ping request to each address within the range
for (quint32 i = 1; i < range; i++) {
quint32 address = addressRangeStart + i;
QHostAddress targetAddress(address);
// Skip our self
if (targetAddress == entry.ip())
continue;
PingReply *reply = m_ping->ping(targetAddress);
m_runningPingRepies.append(reply);
connect(reply, &PingReply::finished, this, [=](){
m_runningPingRepies.removeAll(reply);
if (reply->error() == PingReply::ErrorNoError) {
qCDebug(dcNetworkDeviceDiscovery()) << "Ping response from" << targetAddress.toString() << reply->hostName() << reply->duration() << "ms";
int index = m_currentReply->networkDeviceInfos().indexFromHostAddress(targetAddress);
if (index < 0) {
// Add the network device
NetworkDeviceInfo networkDeviceInfo;
networkDeviceInfo.setAddress(targetAddress);
networkDeviceInfo.setHostName(reply->hostName());
m_currentReply->networkDeviceInfos().append(networkDeviceInfo);
} else {
m_currentReply->networkDeviceInfos()[index].setAddress(targetAddress);
m_currentReply->networkDeviceInfos()[index].setHostName(reply->hostName());
if (!m_currentReply->networkDeviceInfos()[index].networkInterface().isValid()) {
m_currentReply->networkDeviceInfos()[index].setNetworkInterface(NetworkUtils::getInterfaceForHostaddress(targetAddress));
}
}
}
if (m_runningPingRepies.isEmpty() && m_currentReply && !m_discoveryTimer->isActive()) {
finishDiscovery();
}
});
}
}
}
}
void NetworkDeviceDiscovery::finishDiscovery()
{
m_discoveryTimer->stop();
m_running = false;
emit runningChanged(m_running);
// Sort by host address
m_currentReply->networkDeviceInfos().sortNetworkDevices();
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_currentReply->m_startTimestamp;
qCDebug(dcNetworkDeviceDiscovery()) << "Discovery finished. Found" << m_currentReply->networkDeviceInfos().count() << "network devices in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
emit m_currentReply->finished();
m_currentReply->deleteLater();
m_currentReply = nullptr;
}
void NetworkDeviceDiscovery::updateOrAddNetworkDeviceArp(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress, const QString &manufacturer)
{
if (!m_currentReply)
return;
int index = m_currentReply->networkDeviceInfos().indexFromHostAddress(address);
if (index >= 0) {
// Update the network device
m_currentReply->networkDeviceInfos()[index].setMacAddress(macAddress);
if (!manufacturer.isEmpty())
m_currentReply->networkDeviceInfos()[index].setMacAddressManufacturer(manufacturer);
if (interface.isValid()) {
m_currentReply->networkDeviceInfos()[index].setNetworkInterface(interface);
}
} else {
index = m_currentReply->networkDeviceInfos().indexFromMacAddress(macAddress);
if (index >= 0) {
// Update the network device
m_currentReply->networkDeviceInfos()[index].setAddress(address);
if (!manufacturer.isEmpty())
m_currentReply->networkDeviceInfos()[index].setMacAddressManufacturer(manufacturer);
if (interface.isValid()) {
m_currentReply->networkDeviceInfos()[index].setNetworkInterface(interface);
}
} else {
// Add the network device
NetworkDeviceInfo networkDeviceInfo;
networkDeviceInfo.setAddress(address);
networkDeviceInfo.setMacAddress(macAddress);
if (!manufacturer.isEmpty())
networkDeviceInfo.setMacAddressManufacturer(manufacturer);
if (interface.isValid())
networkDeviceInfo.setNetworkInterface(interface);
m_currentReply->networkDeviceInfos().append(networkDeviceInfo);
}
}
}
void NetworkDeviceDiscovery::onArpResponseRceived(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress)
{
if (!m_currentReply) {
qCDebug(dcNetworkDeviceDiscovery()) << "Received ARP reply from" << address.toString() << macAddress << "but there is no discovery running.";
return;
}
qCDebug(dcNetworkDeviceDiscovery()) << "ARP reply received" << address.toString() << macAddress << interface.name();
// Lookup the mac address vendor if possible
if (m_macAddressDatabase->available()) {
MacAddressDatabaseReply *reply = m_macAddressDatabase->lookupMacAddress(macAddress);
connect(reply, &MacAddressDatabaseReply::finished, m_currentReply, [=](){
qCDebug(dcNetworkDeviceDiscovery()) << "MAC manufacturer lookup finished for" << macAddress << ":" << reply->manufacturer();
updateOrAddNetworkDeviceArp(interface, address, macAddress, reply->manufacturer());
});
} else {
updateOrAddNetworkDeviceArp(interface, address, macAddress);
}
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -35,50 +35,39 @@
#include <QObject>
#include <QLoggingCategory>
#include "ping.h"
#include "libnymea.h"
#include "hardwareresource.h"
#include "networkdevicemonitor.h"
#include "pingreply.h"
#include "macaddressdatabasereply.h"
#include "networkdevicediscoveryreply.h"
class ArpSocket;
class MacAddressDatabase;
class MacAddressDatabaseReply;
Q_DECLARE_LOGGING_CATEGORY(dcNetworkDeviceDiscovery)
class LIBNYMEA_EXPORT NetworkDeviceDiscovery : public QObject
class LIBNYMEA_EXPORT NetworkDeviceDiscovery : public HardwareResource
{
Q_OBJECT
public:
explicit NetworkDeviceDiscovery(QObject *parent = nullptr);
virtual ~NetworkDeviceDiscovery() = default;
NetworkDeviceDiscoveryReply *discover();
virtual NetworkDeviceDiscoveryReply *discover() = 0;
bool available() const;
bool running() const;
virtual bool running() const = 0;
PingReply *ping(const QHostAddress &address);
MacAddressDatabaseReply *lookupMacAddress(const QString &macAddress);
virtual NetworkDeviceMonitor *registerMonitor(const QString &macAddress) = 0;
virtual void unregisterMonitor(const QString &macAddress) = 0;
virtual void unregisterMonitor(NetworkDeviceMonitor *networkDeviceMonitor) = 0;
virtual PingReply *ping(const QHostAddress &address) = 0;
virtual MacAddressDatabaseReply *lookupMacAddress(const QString &macAddress) = 0;
virtual bool sendArpRequest(const QHostAddress &address) = 0;
signals:
void runningChanged(bool running);
private:
MacAddressDatabase *m_macAddressDatabase = nullptr;
ArpSocket *m_arpSocket = nullptr;
Ping *m_ping = nullptr;
bool m_running = false;
QTimer *m_discoveryTimer = nullptr;
NetworkDeviceDiscoveryReply *m_currentReply = nullptr;
QList<PingReply *> m_runningPingRepies;
void pingAllNetworkDevices();
void finishDiscovery();
void updateOrAddNetworkDeviceArp(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress, const QString &manufacturer = QString());
private slots:
void onArpResponseRceived(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress);
void networkDeviceInfoCacheUpdated();
};

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -39,19 +39,21 @@
class LIBNYMEA_EXPORT NetworkDeviceDiscoveryReply : public QObject
{
Q_OBJECT
friend class NetworkDeviceDiscovery;
public:
NetworkDeviceInfos &networkDeviceInfos();
explicit NetworkDeviceDiscoveryReply(QObject *parent = nullptr) : QObject(parent) { };
virtual ~NetworkDeviceDiscoveryReply() = default;
virtual NetworkDeviceInfos networkDeviceInfos() const = 0;
virtual NetworkDeviceInfos virtualNetworkDeviceInfos() const = 0;
signals:
void finished();
// Emitted whenever a certain host address has been pinged successfully
void hostAddressDiscovered(const QHostAddress &address);
private:
explicit NetworkDeviceDiscoveryReply(QObject *parent = nullptr);
NetworkDeviceInfos m_networkDeviceInfos;
qint64 m_startTimestamp;
// Emited whenerver a valid NetworkDeviceInfo has been added
void networkDeviceInfoAdded(const NetworkDeviceInfo &networkDeviceInfo);
void finished();
};

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -30,6 +30,7 @@
#include "networkdeviceinfo.h"
NetworkDeviceInfo::NetworkDeviceInfo()
{
@ -38,7 +39,7 @@ NetworkDeviceInfo::NetworkDeviceInfo()
NetworkDeviceInfo::NetworkDeviceInfo(const QString &macAddress):
m_macAddress(macAddress)
{
m_macAddressSet = true;
}
QString NetworkDeviceInfo::macAddress() const
@ -49,6 +50,7 @@ QString NetworkDeviceInfo::macAddress() const
void NetworkDeviceInfo::setMacAddress(const QString &macAddress)
{
m_macAddress = macAddress;
m_macAddressSet = true;
}
QString NetworkDeviceInfo::macAddressManufacturer() const
@ -59,6 +61,7 @@ QString NetworkDeviceInfo::macAddressManufacturer() const
void NetworkDeviceInfo::setMacAddressManufacturer(const QString &macAddressManufacturer)
{
m_macAddressManufacturer = macAddressManufacturer;
m_macAddressManufacturerSet = true;
}
QHostAddress NetworkDeviceInfo::address() const
@ -69,6 +72,7 @@ QHostAddress NetworkDeviceInfo::address() const
void NetworkDeviceInfo::setAddress(const QHostAddress &address)
{
m_address = address;
m_addressSet = true;
}
QString NetworkDeviceInfo::hostName() const
@ -79,6 +83,7 @@ QString NetworkDeviceInfo::hostName() const
void NetworkDeviceInfo::setHostName(const QString &hostName)
{
m_hostName = hostName;
m_hostNameSet = true;
}
QNetworkInterface NetworkDeviceInfo::networkInterface() const
@ -89,6 +94,7 @@ QNetworkInterface NetworkDeviceInfo::networkInterface() const
void NetworkDeviceInfo::setNetworkInterface(const QNetworkInterface &networkInterface)
{
m_networkInterface = networkInterface;
m_networkInterfaceSet = true;
}
bool NetworkDeviceInfo::isValid() const
@ -96,20 +102,34 @@ bool NetworkDeviceInfo::isValid() const
return (!m_address.isNull() || !m_macAddress.isEmpty()) && m_networkInterface.isValid();
}
bool NetworkDeviceInfo::isComplete() const
{
return m_macAddressSet && m_macAddressManufacturerSet && m_addressSet && m_hostNameSet && m_networkInterfaceSet;
}
bool NetworkDeviceInfo::operator==(const NetworkDeviceInfo &other) const
{
return m_macAddress == other.macAddress() &&
m_address == other.address() &&
m_hostName == other.hostName() &&
m_macAddressManufacturer == other.macAddressManufacturer() &&
m_networkInterface.name() == other.networkInterface().name() &&
isComplete() == other.isComplete();
}
QDebug operator<<(QDebug dbg, const NetworkDeviceInfo &networkDeviceInfo)
{
dbg.nospace() << "NetworkDeviceInfo(" << networkDeviceInfo.address().toString();
if (!networkDeviceInfo.hostName().isEmpty())
dbg.nospace() << " (" << networkDeviceInfo.hostName() << ")";
dbg.nospace() << ", " << networkDeviceInfo.macAddress();
if (!networkDeviceInfo.macAddressManufacturer().isEmpty())
dbg.nospace() << " (" << networkDeviceInfo.macAddressManufacturer() << ") ";
if (!networkDeviceInfo.hostName().isEmpty())
dbg.nospace() << ", hostname: " << networkDeviceInfo.hostName();
if (networkDeviceInfo.networkInterface().isValid())
dbg.nospace() << ", " << networkDeviceInfo.networkInterface().name();
dbg.nospace() << ")";
return dbg.space();
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -43,7 +43,6 @@ class LIBNYMEA_EXPORT NetworkDeviceInfo
public:
explicit NetworkDeviceInfo();
explicit NetworkDeviceInfo(const QString &macAddress);
~NetworkDeviceInfo() = default;
QString macAddress() const;
void setMacAddress(const QString &macAddress);
@ -61,6 +60,9 @@ public:
void setNetworkInterface(const QNetworkInterface &networkInterface);
bool isValid() const;
bool isComplete() const;
bool operator==(const NetworkDeviceInfo &other) const;
private:
QHostAddress m_address;
@ -69,8 +71,14 @@ private:
QString m_hostName;
QNetworkInterface m_networkInterface;
bool m_macAddressSet = false;
bool m_macAddressManufacturerSet = false;
bool m_addressSet = false;
bool m_hostNameSet = false;
bool m_networkInterfaceSet = false;
};
QDebug operator<<(QDebug debug, const NetworkDeviceInfo &networkDeviceInfo);

View File

@ -99,6 +99,15 @@ NetworkDeviceInfo NetworkDeviceInfos::get(const QString &macAddress)
return NetworkDeviceInfo();
}
void NetworkDeviceInfos::removeMacAddress(const QString &macAddress)
{
for (int i = 0; i < size(); i++) {
if (at(i).macAddress().toLower() == macAddress.toLower()) {
remove(i);
}
}
}
void NetworkDeviceInfos::sortNetworkDevices()
{
std::sort(this->begin(), this->end(), [](const NetworkDeviceInfo& a, const NetworkDeviceInfo& b) {

View File

@ -52,6 +52,8 @@ public:
NetworkDeviceInfo get(const QHostAddress &address);
NetworkDeviceInfo get(const QString &macAddress);
void removeMacAddress(const QString &macAddress);
void sortNetworkDevices();
NetworkDeviceInfos &operator<<(const NetworkDeviceInfo &networkDeviceInfo);

View File

@ -0,0 +1,52 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkdevicemonitor.h"
#include "networkdeviceinfo.h"
NetworkDeviceMonitor::NetworkDeviceMonitor(QObject *parent) :
QObject(parent)
{
}
QDebug operator<<(QDebug dbg, NetworkDeviceMonitor *networkDeviceMonitor)
{
dbg.nospace() << "NetworkDeviceMonitor(" << networkDeviceMonitor->networkDeviceInfo().macAddress();
if (!networkDeviceMonitor->networkDeviceInfo().macAddressManufacturer().isEmpty())
dbg.nospace() << " - " << networkDeviceMonitor->networkDeviceInfo().macAddressManufacturer();
dbg.nospace() << ", " << networkDeviceMonitor->networkDeviceInfo().address().toString();
dbg.nospace() << ") ";
return dbg.maybeSpace();
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef NETWORKDEVICEMONITOR_H
#define NETWORKDEVICEMONITOR_H
#include <QObject>
#include <QDateTime>
#include "libnymea.h"
#include "networkdeviceinfo.h"
class LIBNYMEA_EXPORT NetworkDeviceMonitor : public QObject
{
Q_OBJECT
public:
explicit NetworkDeviceMonitor(QObject *parent = nullptr);
virtual NetworkDeviceInfo networkDeviceInfo() const = 0;
virtual bool reachable() const = 0;
virtual QDateTime lastSeen() const = 0;
signals:
void reachableChanged(bool reachable);
void lastSeenChanged(const QDateTime &lastSeen);
void networkDeviceInfoChanged(const NetworkDeviceInfo &networkDeviceInfo);
};
QDebug operator<<(QDebug debug, NetworkDeviceMonitor *networkDeviceMonitor);
#endif // NETWORKDEVICEMONITOR_H

View File

@ -411,7 +411,7 @@ void Ping::onHostLookupFinished(const QHostInfo &info)
if (info.error() != QHostInfo::NoError) {
qCWarning(dcPing()) << "Failed to look up hostname after successfull ping" << reply->targetHostAddress().toString() << info.error();
} else {
qCDebug(dcPing()) << "********Looked up hostname after successfull ping" << reply->targetHostAddress().toString() << info.hostName();
qCDebug(dcPing()) << "******** Looked up hostname after successfull ping" << reply->targetHostAddress().toString() << info.hostName();
if (info.hostName() != reply->targetHostAddress().toString()) {
reply->m_hostName = info.hostName();
}
@ -419,4 +419,3 @@ void Ping::onHostLookupFinished(const QHostInfo &info)
finishReply(reply, PingReply::ErrorNoError);
}