diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp
index e873b839..87d52b68 100644
--- a/libnymea-core/hardwaremanagerimplementation.cpp
+++ b/libnymea-core/hardwaremanagerimplementation.cpp
@@ -46,6 +46,7 @@
#include "hardware/modbus/modbusrtumanager.h"
#include "hardware/modbus/modbusrtuhardwareresourceimplementation.h"
+#include "network/networkdevicediscovery.h"
namespace nymeaserver {
@@ -78,6 +79,8 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform,
m_modbusRtuResource = new ModbusRtuHardwareResourceImplementation(modbusRtuManager, this);
+ m_networkDeviceDiscovery = new NetworkDeviceDiscovery(this);
+
// Enable all the resources
setResourceEnabled(m_pluginTimerManager, true);
setResourceEnabled(m_radio433, true);
@@ -100,6 +103,7 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform,
HardwareManagerImplementation::~HardwareManagerImplementation()
{
+
}
Radio433 *HardwareManagerImplementation::radio433()
@@ -152,6 +156,11 @@ ModbusRtuHardwareResource *HardwareManagerImplementation::modbusRtuResource()
return m_modbusRtuResource;
}
+NetworkDeviceDiscovery *HardwareManagerImplementation::networkDeviceDiscovery()
+{
+ return m_networkDeviceDiscovery;
+}
+
void HardwareManagerImplementation::thingsLoaded()
{
m_zigbeeResource->thingsLoaded();
diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h
index c808b0d2..c94153ef 100644
--- a/libnymea-core/hardwaremanagerimplementation.h
+++ b/libnymea-core/hardwaremanagerimplementation.h
@@ -64,6 +64,7 @@ public:
I2CManager *i2cManager() override;
ZigbeeHardwareResource *zigbeeResource() override;
ModbusRtuHardwareResource *modbusRtuResource() override;
+ NetworkDeviceDiscovery *networkDeviceDiscovery() override;
public slots:
void thingsLoaded();
@@ -83,6 +84,8 @@ private:
I2CManager *m_i2cManager = nullptr;
ZigbeeHardwareResourceImplementation *m_zigbeeResource = nullptr;
ModbusRtuHardwareResourceImplementation *m_modbusRtuResource = nullptr;
+ NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
+
};
}
diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h
index 4dab713e..893fa340 100644
--- a/libnymea/hardwaremanager.h
+++ b/libnymea/hardwaremanager.h
@@ -45,6 +45,7 @@ class I2CManager;
class ZigbeeHardwareResource;
class HardwareResource;
class ModbusRtuHardwareResource;
+class NetworkDeviceDiscovery;
class HardwareManager : public QObject
{
@@ -65,6 +66,7 @@ public:
virtual I2CManager *i2cManager() = 0;
virtual ZigbeeHardwareResource *zigbeeResource() = 0;
virtual ModbusRtuHardwareResource *modbusRtuResource() = 0;
+ virtual NetworkDeviceDiscovery *networkDeviceDiscovery() = 0;
protected:
void setResourceEnabled(HardwareResource* resource, bool enabled);
diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro
index 411dcf87..bae23e8e 100644
--- a/libnymea/libnymea.pro
+++ b/libnymea/libnymea.pro
@@ -43,6 +43,11 @@ HEADERS += \
network/apikeys/apikeysprovider.h \
network/apikeys/apikeystorage.h \
network/arpsocket.h \
+ network/networkdevice.h \
+ network/networkdevicediscovery.h \
+ network/networkdevicediscoveryreply.h \
+ network/networkdevices.h \
+ network/networkutils.h \
network/ping.h \
network/pingreply.h \
platform/package.h \
@@ -144,6 +149,11 @@ SOURCES += \
network/apikeys/apikeysprovider.cpp \
network/apikeys/apikeystorage.cpp \
network/arpsocket.cpp \
+ network/networkdevice.cpp \
+ network/networkdevicediscovery.cpp \
+ network/networkdevicediscoveryreply.cpp \
+ network/networkdevices.cpp \
+ network/networkutils.cpp \
network/ping.cpp \
network/pingreply.cpp \
nymeasettings.cpp \
diff --git a/libnymea/network/arpsocket.cpp b/libnymea/network/arpsocket.cpp
index 0543eeda..ab1ef1bc 100644
--- a/libnymea/network/arpsocket.cpp
+++ b/libnymea/network/arpsocket.cpp
@@ -1,5 +1,36 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 "arpsocket.h"
#include "loggingcategories.h"
+#include "networkutils.h"
#include
#include
@@ -161,7 +192,7 @@ bool ArpSocket::isOpen() const
bool ArpSocket::openSocket()
{
- qCDebug(dcArpSocket()) << "Enabeling ARP scanner...";
+ qCDebug(dcArpSocket()) << "Open ARP socket...";
if (m_isOpen) {
qCWarning(dcArpSocket()) << "Failed to enable ARP scanner because the scanner is already running.";
@@ -220,7 +251,7 @@ bool ArpSocket::openSocket()
//qCDebug(dcArpSocket()) << "ARP request from " << senderMacAddress << senderHostAddress.toString() << "-->" << targetMacAddress << targetHostAddress.toString();
break;
case ARPOP_REPLY: {
- QNetworkInterface networkInterface = getInterfaceForMacAddress(targetMacAddress);
+ QNetworkInterface networkInterface = NetworkUtils::getInterfaceForMacAddress(targetMacAddress);
if (!networkInterface.isValid()) {
qCWarning(dcArpSocket()) << "Could not find interface from ARP response" << targetHostAddress.toString() << targetMacAddress;
return;
@@ -364,30 +395,3 @@ void ArpSocket::fillHostAddress(uint8_t *targetArray, const QHostAddress &hostAd
}
}
-QNetworkInterface ArpSocket::getInterfaceForHostaddress(const QHostAddress &address)
-{
- foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
- foreach (const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
- // Only IPv4
- if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol)
- continue;
-
- if (address.isInSubnet(entry.ip(), entry.netmask().toIPv4Address())) {
- return networkInterface;
- }
- }
- }
-
- return QNetworkInterface();
-}
-
-QNetworkInterface ArpSocket::getInterfaceForMacAddress(const QString &macAddress)
-{
- foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
- if (networkInterface.hardwareAddress().toLower() == macAddress.toLower()) {
- return networkInterface;
- }
- }
-
- return QNetworkInterface();
-}
diff --git a/libnymea/network/arpsocket.h b/libnymea/network/arpsocket.h
index d910d27e..4cea59fd 100644
--- a/libnymea/network/arpsocket.h
+++ b/libnymea/network/arpsocket.h
@@ -1,3 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 ARPSOCKET_H
#define ARPSOCKET_H
@@ -8,7 +38,9 @@
#include
#include
-class ArpSocket : public QObject
+#include "libnymea.h"
+
+class LIBNYMEA_EXPORT ArpSocket : public QObject
{
Q_OBJECT
public:
@@ -47,8 +79,6 @@ private:
void fillMacAddress(uint8_t *targetArray, const QString &macAddress);
void fillHostAddress(uint8_t *targetArray, const QHostAddress &hostAddress);
- QNetworkInterface getInterfaceForHostaddress(const QHostAddress &address);
- QNetworkInterface getInterfaceForMacAddress(const QString &macAddress);
};
#endif // ARPSOCKET_H
diff --git a/libnymea/network/networkdevice.cpp b/libnymea/network/networkdevice.cpp
new file mode 100644
index 00000000..4e516dc6
--- /dev/null
+++ b/libnymea/network/networkdevice.cpp
@@ -0,0 +1,116 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 "networkdevice.h"
+
+NetworkDevice::NetworkDevice()
+{
+
+}
+
+NetworkDevice::NetworkDevice(const QString &macAddress):
+ m_macAddress(macAddress)
+{
+
+}
+
+QString NetworkDevice::macAddress() const
+{
+ return m_macAddress;
+}
+
+void NetworkDevice::setMacAddress(const QString &macAddress)
+{
+ m_macAddress = macAddress;
+}
+
+QString NetworkDevice::macAddressManufacturer() const
+{
+ return m_macAddressManufacturer;
+}
+
+void NetworkDevice::setMacAddressManufacturer(const QString &macAddressManufacturer)
+{
+ m_macAddressManufacturer = macAddressManufacturer;
+}
+
+QHostAddress NetworkDevice::address() const
+{
+ return m_address;
+}
+
+void NetworkDevice::setAddress(const QHostAddress &address)
+{
+ m_address = address;
+}
+
+QString NetworkDevice::hostName() const
+{
+ return m_hostName;
+}
+
+void NetworkDevice::setHostName(const QString &hostName)
+{
+ m_hostName = hostName;
+}
+
+QNetworkInterface NetworkDevice::networkInterface() const
+{
+ return m_networkInterface;
+}
+
+void NetworkDevice::setNetworkInterface(const QNetworkInterface &networkInterface)
+{
+ m_networkInterface = networkInterface;
+}
+
+bool NetworkDevice::isValid() const
+{
+ return (!m_address.isNull() || !m_macAddress.isEmpty()) && m_networkInterface.isValid();
+}
+
+QDebug operator<<(QDebug dbg, const NetworkDevice &networkDevice)
+{
+ dbg.nospace() << "NetworkDevice(";
+ dbg.nospace() << networkDevice.address().toString() << ", ";
+ dbg.nospace() << networkDevice.macAddress();
+ if (!networkDevice.macAddressManufacturer().isEmpty())
+ dbg.nospace() << "(" << networkDevice.macAddressManufacturer() << ")";
+
+ if (!networkDevice.hostName().isEmpty())
+ dbg.nospace() << ", " << networkDevice.hostName();
+
+ if (networkDevice.networkInterface().isValid())
+ dbg.nospace() << ", " << networkDevice.networkInterface().name();
+
+ dbg.nospace() << ")";
+ return dbg.space();
+}
+
diff --git a/libnymea/network/networkdevice.h b/libnymea/network/networkdevice.h
new file mode 100644
index 00000000..a2e57395
--- /dev/null
+++ b/libnymea/network/networkdevice.h
@@ -0,0 +1,76 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 NETWORKDEVICE_H
+#define NETWORKDEVICE_H
+
+#include
+#include
+#include
+#include
+
+#include "libnymea.h"
+
+class LIBNYMEA_EXPORT NetworkDevice
+{
+public:
+ explicit NetworkDevice();
+ explicit NetworkDevice(const QString &macAddress);
+
+ QString macAddress() const;
+ void setMacAddress(const QString &macAddress);
+
+ QString macAddressManufacturer() const;
+ void setMacAddressManufacturer(const QString &macAddressManufacturer);
+
+ QHostAddress address() const;
+ void setAddress(const QHostAddress &address);
+
+ QString hostName() const;
+ void setHostName(const QString &hostName);
+
+ QNetworkInterface networkInterface() const;
+ void setNetworkInterface(const QNetworkInterface &networkInterface);
+
+ bool isValid() const;
+
+private:
+ QHostAddress m_address;
+ QString m_macAddress;
+ QString m_macAddressManufacturer;
+ QString m_hostName;
+ QNetworkInterface m_networkInterface;
+
+};
+
+QDebug operator<<(QDebug debug, const NetworkDevice &networkDevice);
+
+
+#endif // NETWORKDEVICE_H
diff --git a/libnymea/network/networkdevicediscovery.cpp b/libnymea/network/networkdevicediscovery.cpp
new file mode 100644
index 00000000..52b14798
--- /dev/null
+++ b/libnymea/network/networkdevicediscovery.cpp
@@ -0,0 +1,224 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 "networkdevicediscovery.h"
+#include "loggingcategories.h"
+#include "networkutils.h"
+
+NYMEA_LOGGING_CATEGORY(dcNetworkDeviceDiscovery, "NetworkDeviceDiscovery")
+
+NetworkDeviceDiscovery::NetworkDeviceDiscovery(QObject *parent) :
+ QObject(parent)
+{
+ m_arpSocket = new ArpSocket(this);
+ connect(m_arpSocket, &ArpSocket::arpResponse, this, &NetworkDeviceDiscovery::onArpResponseRceived);
+
+ if (!m_arpSocket->openSocket()) {
+ qCWarning(dcNetworkDeviceDiscovery()) << "Network discovery will not make use of ARP packages.";
+ m_arpSocket->closeSocket();
+ }
+
+ m_ping = new Ping(this);
+ if (!m_ping->available())
+ qCWarning(dcNetworkDeviceDiscovery()) << "Failed to create ping tool" << m_ping->error();
+
+ m_discoveryTimer = new QTimer(this);
+ m_discoveryTimer->setInterval(5000);
+ m_discoveryTimer->setSingleShot(true);
+ connect(m_discoveryTimer, &QTimer::timeout, this, [=](){
+ if (m_runningPingRepies.isEmpty() && m_currentReply) {
+ finishDiscovery();
+ }
+ });
+
+ 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;
+
+ 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);
+}
+
+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->networkDevices().indexFromHostAddress(targetAddress);
+ if (index < 0) {
+ // Add the network device
+ NetworkDevice networkDevice;
+ networkDevice.setAddress(targetAddress);
+ networkDevice.setHostName(reply->hostName());
+ m_currentReply->networkDevices().append(networkDevice);
+ } else {
+ m_currentReply->networkDevices()[index].setAddress(targetAddress);
+ m_currentReply->networkDevices()[index].setHostName(reply->hostName());
+ if (!m_currentReply->networkDevices()[index].networkInterface().isValid()) {
+ m_currentReply->networkDevices()[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);
+
+ qCDebug(dcNetworkDeviceDiscovery()) << "Discovery finished. Found" << m_currentReply->networkDevices().count() << "network devices.";
+ m_arpSocket->closeSocket();
+ emit m_currentReply->finished();
+ m_currentReply->deleteLater();
+ m_currentReply = nullptr;
+}
+
+void NetworkDeviceDiscovery::onArpResponseRceived(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress)
+{
+ if (!m_currentReply) {
+ qCDebug(dcNetworkDeviceDiscovery()) << "Received ARP reply but there is no discovery running.";
+ return;
+ }
+
+ qCDebug(dcNetworkDeviceDiscovery()) << "ARP reply received" << address.toString() << macAddress << interface.name();
+ // Update or add network device
+ int index = m_currentReply->networkDevices().indexFromHostAddress(address);
+ if (index >= 0) {
+ // Update the network device
+ m_currentReply->networkDevices()[index].setMacAddress(macAddress);
+ if (interface.isValid()) {
+ m_currentReply->networkDevices()[index].setNetworkInterface(interface);
+ }
+ } else {
+ index = m_currentReply->networkDevices().indexFromMacAddress(macAddress);
+ if (index >= 0) {
+ // Update the network device
+ m_currentReply->networkDevices()[index].setAddress(address);
+ if (interface.isValid()) {
+ m_currentReply->networkDevices()[index].setNetworkInterface(interface);
+ }
+ } else {
+ // Add the network device
+ NetworkDevice networkDevice;
+ networkDevice.setAddress(address);
+ networkDevice.setMacAddress(macAddress);
+ if (interface.isValid())
+ networkDevice.setNetworkInterface(interface);
+
+ m_currentReply->networkDevices().append(networkDevice);
+ }
+ }
+}
diff --git a/libnymea/network/networkdevicediscovery.h b/libnymea/network/networkdevicediscovery.h
new file mode 100644
index 00000000..0d426383
--- /dev/null
+++ b/libnymea/network/networkdevicediscovery.h
@@ -0,0 +1,78 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 NETWORKDEVICEDISCOVERY_H
+#define NETWORKDEVICEDISCOVERY_H
+
+#include
+#include
+#include
+
+#include "ping.h"
+#include "libnymea.h"
+#include "arpsocket.h"
+#include "networkdevicediscoveryreply.h"
+
+Q_DECLARE_LOGGING_CATEGORY(dcNetworkDeviceDiscovery)
+
+class LIBNYMEA_EXPORT NetworkDeviceDiscovery : public QObject
+{
+ Q_OBJECT
+public:
+ explicit NetworkDeviceDiscovery(QObject *parent = nullptr);
+
+ NetworkDeviceDiscoveryReply *discover();
+
+ bool available() const;
+ bool running() const;
+
+ PingReply *ping(const QHostAddress &address);
+
+signals:
+ void runningChanged(bool running);
+
+private:
+ ArpSocket *m_arpSocket = nullptr;
+ Ping *m_ping = nullptr;
+ bool m_running = false;
+
+ QTimer *m_discoveryTimer = nullptr;
+ NetworkDeviceDiscoveryReply *m_currentReply = nullptr;
+ QList m_runningPingRepies;
+
+ void pingAllNetworkDevices();
+ void finishDiscovery();
+
+private slots:
+ void onArpResponseRceived(const QNetworkInterface &interface, const QHostAddress &address, const QString &macAddress);
+
+};
+
+#endif // NETWORKDEVICEDISCOVERY_H
diff --git a/libnymea/network/networkdevicediscoveryreply.cpp b/libnymea/network/networkdevicediscoveryreply.cpp
new file mode 100644
index 00000000..71f7a453
--- /dev/null
+++ b/libnymea/network/networkdevicediscoveryreply.cpp
@@ -0,0 +1,42 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 "networkdevicediscoveryreply.h"
+
+NetworkDeviceDiscoveryReply::NetworkDeviceDiscoveryReply(QObject *parent) :
+ QObject(parent)
+{
+
+}
+
+NetworkDevices &NetworkDeviceDiscoveryReply::networkDevices()
+{
+ return m_networkDevices;
+}
diff --git a/libnymea/network/networkdevicediscoveryreply.h b/libnymea/network/networkdevicediscoveryreply.h
new file mode 100644
index 00000000..1787c02e
--- /dev/null
+++ b/libnymea/network/networkdevicediscoveryreply.h
@@ -0,0 +1,58 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 NETWORKDEVICEDISCOVERYREPLY_H
+#define NETWORKDEVICEDISCOVERYREPLY_H
+
+#include
+
+#include "libnymea.h"
+#include "networkdevices.h"
+
+class LIBNYMEA_EXPORT NetworkDeviceDiscoveryReply : public QObject
+{
+ Q_OBJECT
+
+ friend class NetworkDeviceDiscovery;
+
+public:
+ explicit NetworkDeviceDiscoveryReply(QObject *parent = nullptr);
+
+ NetworkDevices &networkDevices();
+
+signals:
+ void finished();
+
+private:
+ NetworkDevices m_networkDevices;
+
+};
+
+#endif // NETWORKDEVICEDISCOVERYREPLY_H
diff --git a/libnymea/network/networkdevices.cpp b/libnymea/network/networkdevices.cpp
new file mode 100644
index 00000000..8f940f8e
--- /dev/null
+++ b/libnymea/network/networkdevices.cpp
@@ -0,0 +1,103 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 "networkdevices.h"
+
+NetworkDevices::NetworkDevices() :
+ QList()
+{
+
+}
+
+NetworkDevices::NetworkDevices(const QList &other) :
+ QList(other)
+{
+
+}
+
+NetworkDevices NetworkDevices::operator<<(const NetworkDevice &networkDevice)
+{
+ this->append(networkDevice);
+ return *this;
+}
+
+int NetworkDevices::indexFromHostAddress(const QHostAddress &address)
+{
+ for (int i = 0; i < this->size(); i++) {
+ if (at(i).address().toIPv4Address() == address.toIPv4Address()) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int NetworkDevices::indexFromMacAddress(const QString &macAddress)
+{
+ for (int i = 0; i < size(); i++) {
+ if (at(i).macAddress().toLower() == macAddress.toLower()) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+bool NetworkDevices::hasHostAddress(const QHostAddress &address)
+{
+ return indexFromHostAddress(address) >= 0;
+}
+
+bool NetworkDevices::hasMacAddress(const QString &macAddress)
+{
+ return indexFromMacAddress(macAddress) >= 0;
+}
+
+NetworkDevice NetworkDevices::get(const QHostAddress &address)
+{
+ foreach (const NetworkDevice &networkDevice, *this) {
+ if (networkDevice.address() == address) {
+ return networkDevice;
+ }
+ }
+
+ return NetworkDevice();
+}
+
+NetworkDevice NetworkDevices::get(const QString &macAddress)
+{
+ foreach (const NetworkDevice &networkDevice, *this) {
+ if (networkDevice.macAddress() == macAddress) {
+ return networkDevice;
+ }
+ }
+
+ return NetworkDevice();
+}
diff --git a/libnymea/network/networkdevices.h b/libnymea/network/networkdevices.h
new file mode 100644
index 00000000..8d3fc2cc
--- /dev/null
+++ b/libnymea/network/networkdevices.h
@@ -0,0 +1,59 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 NETWORKDEVICES_H
+#define NETWORKDEVICES_H
+
+#include
+
+#include "libnymea.h"
+#include "networkdevice.h"
+
+class LIBNYMEA_EXPORT NetworkDevices : public QList
+{
+
+public:
+ explicit NetworkDevices();
+ NetworkDevices(const QList &other);
+
+ NetworkDevices operator<<(const NetworkDevice &networkDevice);
+
+ int indexFromHostAddress(const QHostAddress &address);
+ int indexFromMacAddress(const QString &macAddress);
+
+ bool hasHostAddress(const QHostAddress &address);
+ bool hasMacAddress(const QString &macAddress);
+
+ NetworkDevice get(const QHostAddress &address);
+ NetworkDevice get(const QString &macAddress);
+
+};
+
+#endif // NETWORKDEVICES_H
diff --git a/libnymea/network/networkutils.cpp b/libnymea/network/networkutils.cpp
new file mode 100644
index 00000000..ddcf1f38
--- /dev/null
+++ b/libnymea/network/networkutils.cpp
@@ -0,0 +1,34 @@
+#include "networkutils.h"
+
+NetworkUtils::NetworkUtils()
+{
+
+}
+
+QNetworkInterface NetworkUtils::getInterfaceForHostaddress(const QHostAddress &address)
+{
+ foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
+ foreach (const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
+ // Only IPv4
+ if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol)
+ continue;
+
+ if (address.isInSubnet(entry.ip(), entry.netmask().toIPv4Address())) {
+ return networkInterface;
+ }
+ }
+ }
+
+ return QNetworkInterface();
+}
+
+QNetworkInterface NetworkUtils::getInterfaceForMacAddress(const QString &macAddress)
+{
+ foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
+ if (networkInterface.hardwareAddress().toLower() == macAddress.toLower()) {
+ return networkInterface;
+ }
+ }
+
+ return QNetworkInterface();
+}
diff --git a/libnymea/network/networkutils.h b/libnymea/network/networkutils.h
new file mode 100644
index 00000000..b75aaedb
--- /dev/null
+++ b/libnymea/network/networkutils.h
@@ -0,0 +1,46 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2021, 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 .
+*
+* 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 NETWORKUTILS_H
+#define NETWORKUTILS_H
+
+#include
+#include
+
+class NetworkUtils
+{
+public:
+ NetworkUtils();
+
+ static QNetworkInterface getInterfaceForHostaddress(const QHostAddress &address);
+ static QNetworkInterface getInterfaceForMacAddress(const QString &macAddress);
+};
+
+#endif // NETWORKUTILS_H
diff --git a/libnymea/network/ping.cpp b/libnymea/network/ping.cpp
index 35aa04f8..c26b2914 100644
--- a/libnymea/network/ping.cpp
+++ b/libnymea/network/ping.cpp
@@ -29,6 +29,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "ping.h"
+#include "networkutils.h"
#include "loggingcategories.h"
#include
@@ -115,7 +116,7 @@ PingReply *Ping::ping(const QHostAddress &hostAddress)
{
PingReply *reply = new PingReply(this);
reply->m_targetHostAddress = hostAddress;
- reply->m_networkInterface = getInterfaceForHostaddress(hostAddress);
+ reply->m_networkInterface = NetworkUtils::getInterfaceForHostaddress(hostAddress);
// Perform the reply in the next event loop to give the user time to do the reply connects
m_replyQueue.enqueue(reply);
@@ -284,34 +285,6 @@ void Ping::finishReply(PingReply *reply, PingReply::Error error)
reply->deleteLater();
}
-QNetworkInterface Ping::getInterfaceForHostaddress(const QHostAddress &address)
-{
- foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
- foreach (const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
- // Only IPv4
- if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol)
- continue;
-
- if (address.isInSubnet(entry.ip(), entry.netmask().toIPv4Address())) {
- return networkInterface;
- }
- }
- }
-
- return QNetworkInterface();
-}
-
-QNetworkInterface Ping::getInterfaceForMacAddress(const QString &macAddress)
-{
- foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
- if (networkInterface.hardwareAddress().toLower() == macAddress.toLower()) {
- return networkInterface;
- }
- }
-
- return QNetworkInterface();
-}
-
void Ping::onSocketReadyRead(int socketDescriptor)
{
// We must read all data otherwise the socket notifier does not work as expected
diff --git a/libnymea/network/ping.h b/libnymea/network/ping.h
index df673e9a..3ce13f84 100644
--- a/libnymea/network/ping.h
+++ b/libnymea/network/ping.h
@@ -101,9 +101,6 @@ private:
void finishReply(PingReply *reply, PingReply::Error error);
- QNetworkInterface getInterfaceForHostaddress(const QHostAddress &address);
- QNetworkInterface getInterfaceForMacAddress(const QString &macAddress);
-
private slots:
void onSocketReadyRead(int socketDescriptor);
diff --git a/libnymea/network/pingreply.h b/libnymea/network/pingreply.h
index da57b41b..e1c8d9c2 100644
--- a/libnymea/network/pingreply.h
+++ b/libnymea/network/pingreply.h
@@ -37,10 +37,12 @@
#include
+#include "libnymea.h"
+
#include
#include
-class PingReply : public QObject
+class LIBNYMEA_EXPORT PingReply : public QObject
{
Q_OBJECT