summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-09-05 09:02:02 +0200
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-09-05 09:02:03 +0200
commite4edadd2dcb0a7a20cdcfa7d4b4b2a2415227245 (patch)
treecd2adefedba016885a44f50ceaac4eeadab7aaef
parent0e4c4e4ddc707384e44e68c3a77479ba11bf61b1 (diff)
parentdf0ba9b97c26901f52769381df3c4cbf1fae9ca6 (diff)
Merge remote-tracking branch 'origin/5.14' into 5.15
-rw-r--r--config.tests/compiletest/compiletest.pro7
-rw-r--r--examples/knx/device/mainwindow.cpp12
-rw-r--r--examples/knx/discoverer/main.cpp37
-rw-r--r--examples/knx/feature/mainwindow.cpp12
-rw-r--r--examples/knx/group/mainwindow.cpp12
-rw-r--r--examples/knx/router/main.cpp13
-rw-r--r--src/knx/core/qknxbytearray.cpp3
-rw-r--r--src/knx/core/qknxbytearray.h5
-rw-r--r--src/knx/netip/netip.pri1
-rw-r--r--src/knx/netip/qknxnetipconnectionheader.cpp2
-rw-r--r--src/knx/netip/qknxnetiproutingindication.cpp2
-rw-r--r--src/knx/netip/qknxnetipserverdiscoveryagent.cpp389
-rw-r--r--src/knx/netip/qknxnetipserverdiscoveryagent.h18
-rw-r--r--src/knx/netip/qknxnetipserverdiscoveryagent_p.cpp684
-rw-r--r--src/knx/netip/qknxnetipserverdiscoveryagent_p.h97
-rw-r--r--src/knx/netip/qknxnetipserverinfo.cpp49
-rw-r--r--src/knx/netip/qknxnetipserverinfo.h20
-rw-r--r--src/knx/netip/qknxnetipserverinfo_p.h6
-rw-r--r--src/knx/qknxdevicemanagementframe.cpp13
-rw-r--r--src/knx/ssl/qknxsecurekey.cpp4
-rw-r--r--tests/auto/qknxnetipcri/tst_qknxnetipcri.cpp2
-rw-r--r--tests/auto/qknxnetiprouter/tst_qknxnetiprouter.cpp2
-rw-r--r--tests/auto/qknxtunnelframefactory/tst_qknxtunnelframefactory.cpp2
23 files changed, 974 insertions, 418 deletions
diff --git a/config.tests/compiletest/compiletest.pro b/config.tests/compiletest/compiletest.pro
index b4d29a1..66f8581 100644
--- a/config.tests/compiletest/compiletest.pro
+++ b/config.tests/compiletest/compiletest.pro
@@ -1,8 +1,5 @@
-gcc {
- versionAtLeast(QT_GCC_MAJOR_VERSION, 5) \
- SOURCES += main.cpp
- else: \
- SOURCES += main_less_5.cpp
+ gcc:!clang:lessThan(QT_GCC_MAJOR_VERSION, 5) {
+ SOURCES += main_less_5.cpp
} else {
SOURCES += main.cpp
}
diff --git a/examples/knx/device/mainwindow.cpp b/examples/knx/device/mainwindow.cpp
index 54d3b6a..f1516a2 100644
--- a/examples/knx/device/mainwindow.cpp
+++ b/examples/knx/device/mainwindow.cpp
@@ -170,13 +170,16 @@ void MainWindow::on_actionImport_triggered()
on_devices_currentIndexChanged(ui->devices->currentIndex());
}
-void MainWindow::on_devices_currentIndexChanged(int /* index */)
+void MainWindow::on_devices_currentIndexChanged(int index)
{
delete m_device;
+ m_device = nullptr;
ui->secureConfigs->clear();
- const auto model = qobject_cast<QStandardItemModel*>(ui->devices->model());
- m_device = static_cast<DeviceItem *> (model->item(ui->devices->currentIndex()))->clone();
+ if (index >= 0) {
+ const auto model = qobject_cast<QStandardItemModel*>(ui->devices->model());
+ m_device = static_cast<DeviceItem *> (model->item(ui->devices->currentIndex()))->clone();
+ }
if (m_device) {
const auto deviceInfo = m_device->info();
@@ -190,6 +193,8 @@ void MainWindow::on_devices_currentIndexChanged(int /* index */)
.arg(config.userId())
.arg(ia.isValid() ? ia.toString() : tr("No specific address")), i);
}
+ } else {
+ m_device = new DeviceItem({});
}
ui->secureConfigs->setEnabled(bool(ui->secureConfigs->count())
@@ -311,6 +316,7 @@ void MainWindow::setupInterfaces()
if (i < 0)
return;
m_discoveryAgent.stop();
+ ui->devices->clear();
m_discoveryAgent.setLocalAddress(QHostAddress(ui->interfaces->currentData()
.toStringList().first()));
m_discoveryAgent.start();
diff --git a/examples/knx/discoverer/main.cpp b/examples/knx/discoverer/main.cpp
index 3cf564b..d9944cb 100644
--- a/examples/knx/discoverer/main.cpp
+++ b/examples/knx/discoverer/main.cpp
@@ -56,8 +56,6 @@
#include <QtKnx/QKnxNetIpServerDiscoveryAgent>
#include <QtKnx/QKnxNetIpSrpBuilder>
-#include <QtNetwork/QNetworkInterface>
-
static QString familyToString(QKnxNetIp::ServiceFamily id)
{
switch (id) {
@@ -83,17 +81,6 @@ static QString familyToString(QKnxNetIp::ServiceFamily id)
return "Unknown";
}
-QString interfaceFromAddress(const QHostAddress &address)
-{
- auto interfaces = QNetworkInterface::allInterfaces();
- for (const auto &interface : qAsConst(interfaces)) {
- if (interface.allAddresses().contains(address))
- return interface.humanReadableName();
- }
- return QString(address == QHostAddress(QKnxNetIp::Constants::MulticastAddress)
- ? "Multicast" : "Unknown");
-}
-
int main(int argc, char *argv[])
{
QCoreApplication discoverer(argc, argv);
@@ -130,10 +117,8 @@ int main(int argc, char *argv[])
agent.setLocalPort(parser.value("localPort").toUInt());
agent.setTimeout(parser.value("timeout").toInt() * 1000);
- if (parser.isSet("localAddress")) {
+ if (parser.isSet("localAddress"))
agent.setLocalAddress(QHostAddress(parser.value("localAddress")));
- agent.setResponseType(QKnxNetIpServerDiscoveryAgent::ResponseType::Unicast);
- }
if (parser.isSet("unicast"))
agent.setResponseType(QKnxNetIpServerDiscoveryAgent::ResponseType::Unicast);
@@ -189,21 +174,25 @@ int main(int argc, char *argv[])
QObject::connect(&agent, &QKnxNetIpServerDiscoveryAgent::finished, &discoverer,
&QCoreApplication::quit);
- agent.start();
-
- if (agent.error() == QKnxNetIpServerDiscoveryAgent::Error::None)
- discoverer.exec();
+ if (!parser.isSet("localAddress")) {
+ agent.start(QKnxNetIpServerDiscoveryAgent::InterfaceType::Ethernet
+ | QKnxNetIpServerDiscoveryAgent::InterfaceType::Wifi);
+ } else {
+ agent.start(QVector<QHostAddress> { agent.localAddress() });
+ }
- qInfo().noquote() << endl << "Device used to send the search request:";
- qInfo().noquote() << QString::fromLatin1(" Network interface: %1, address: %2, port: %3")
- .arg(interfaceFromAddress(agent.localAddress()), agent.localAddress().toString())
- .arg(agent.localPort());
+ if (agent.error() == QKnxNetIpServerDiscoveryAgent::Error::None
+ && agent.state() == QKnxNetIpServerDiscoveryAgent::State::Running) {
+ discoverer.exec();
+ }
const auto servers = agent.discoveredServers();
if (servers.size() > 0) {
qInfo().noquote() << endl << QString::fromLatin1("%1 server(s) found on the network.")
.arg(servers.size());
for (auto server : servers) {
+ qInfo().noquote() << QString::fromLatin1(" Network interface: %1, address: %2")
+ .arg(server.networkInterface().humanReadableName(), server.hostAddress().toString());
qInfo().noquote() << QString::fromLatin1(" Server: %1").arg(server.deviceName());
qInfo().noquote() << QString::fromLatin1(" Individual address: %1").arg(server
.individualAddress().toString());
diff --git a/examples/knx/feature/mainwindow.cpp b/examples/knx/feature/mainwindow.cpp
index 7e44327..8f32b06 100644
--- a/examples/knx/feature/mainwindow.cpp
+++ b/examples/knx/feature/mainwindow.cpp
@@ -170,13 +170,16 @@ void MainWindow::on_actionImport_triggered()
on_devices_currentIndexChanged(ui->devices->currentIndex());
}
-void MainWindow::on_devices_currentIndexChanged(int /* index */)
+void MainWindow::on_devices_currentIndexChanged(int index)
{
delete m_device;
+ m_device = nullptr;
ui->secureConfigs->clear();
- const auto model = qobject_cast<QStandardItemModel*>(ui->devices->model());
- m_device = static_cast<DeviceItem *> (model->item(ui->devices->currentIndex()))->clone();
+ if (index >= 0) {
+ const auto model = qobject_cast<QStandardItemModel*>(ui->devices->model());
+ m_device = static_cast<DeviceItem *> (model->item(ui->devices->currentIndex()))->clone();
+ }
if (m_device) {
const auto deviceInfo = m_device->info();
@@ -190,6 +193,8 @@ void MainWindow::on_devices_currentIndexChanged(int /* index */)
.arg(config.userId())
.arg(ia.isValid() ? ia.toString() : tr("No specific address")), i);
}
+ } else {
+ m_device = new DeviceItem({});
}
ui->secureConfigs->setEnabled(bool(ui->secureConfigs->count())
@@ -280,6 +285,7 @@ void MainWindow::setupInterfaces()
if (i < 0)
return;
m_discoveryAgent.stop();
+ ui->devices->clear();
m_discoveryAgent.setLocalAddress(QHostAddress(ui->interfaces->currentData()
.toStringList().first()));
m_discoveryAgent.start();
diff --git a/examples/knx/group/mainwindow.cpp b/examples/knx/group/mainwindow.cpp
index 4100e03..2e297af 100644
--- a/examples/knx/group/mainwindow.cpp
+++ b/examples/knx/group/mainwindow.cpp
@@ -169,13 +169,16 @@ void MainWindow::on_actionImport_triggered()
on_devices_currentIndexChanged(ui->devices->currentIndex());
}
-void MainWindow::on_devices_currentIndexChanged(int /* index */)
+void MainWindow::on_devices_currentIndexChanged(int index)
{
delete m_device;
+ m_device = nullptr;
ui->secureConfigs->clear();
- const auto model = qobject_cast<QStandardItemModel*>(ui->devices->model());
- m_device = static_cast<DeviceItem *> (model->item(ui->devices->currentIndex()))->clone();
+ if (index >= 0) {
+ const auto model = qobject_cast<QStandardItemModel*>(ui->devices->model());
+ m_device = static_cast<DeviceItem *> (model->item(ui->devices->currentIndex()))->clone();
+ }
if (m_device) {
const auto deviceInfo = m_device->info();
@@ -189,6 +192,8 @@ void MainWindow::on_devices_currentIndexChanged(int /* index */)
.arg(config.userId())
.arg(ia.isValid() ? ia.toString() : tr("No specific address")), i);
}
+ } else {
+ m_device = new DeviceItem({});
}
ui->secureConfigs->setEnabled(bool(ui->secureConfigs->count())
@@ -288,6 +293,7 @@ void MainWindow::setupInterfaces()
if (i < 0)
return;
m_discoveryAgent.stop();
+ ui->devices->clear();
m_discoveryAgent.setLocalAddress(QHostAddress(ui->interfaces->currentData()
.toStringList().first()));
m_discoveryAgent.start();
diff --git a/examples/knx/router/main.cpp b/examples/knx/router/main.cpp
index f9ccc9a..5218661 100644
--- a/examples/knx/router/main.cpp
+++ b/examples/knx/router/main.cpp
@@ -238,14 +238,13 @@ int main(int argc, char *argv[])
QNetworkInterface iface { QNetworkInterface::interfaceFromName(cliParser.value("interface")) };
if (!iface.isValid()) {
auto interfaces = iface.allInterfaces();
- QList<QNetworkInterface>::iterator found = ( std::find_if(interfaces.begin(),
- interfaces.end(),
- [](const QNetworkInterface &i){
- return i.type() == QNetworkInterface::Ethernet;
- }));
+ QList<QNetworkInterface>::iterator found = std::find_if(
+ interfaces.begin(), interfaces.end(), [](const QNetworkInterface &i) {
+ return i.type() == QNetworkInterface::Ethernet;
+ }
+ );
if (found == iface.allInterfaces().end()) {
- qInfo().noquote() << "No valid network interface given and no "
- "Ethernet adapter found. ";
+ qInfo().noquote() << "No valid network interface given and no Ethernet adapter found.";
cliParser.showHelp();
}
iface = static_cast<QNetworkInterface>(*found);
diff --git a/src/knx/core/qknxbytearray.cpp b/src/knx/core/qknxbytearray.cpp
index 6a573d6..53ed547 100644
--- a/src/knx/core/qknxbytearray.cpp
+++ b/src/knx/core/qknxbytearray.cpp
@@ -243,6 +243,9 @@ void QKnxByteArray::clear()
*/
void QKnxByteArray::resize(int size)
{
+ if (size == m_bytes.size())
+ return;
+
if (size > m_bytes.size())
m_bytes.append(size - m_bytes.size(), 0x00);
else
diff --git a/src/knx/core/qknxbytearray.h b/src/knx/core/qknxbytearray.h
index 4f1fdb1..efc1a02 100644
--- a/src/knx/core/qknxbytearray.h
+++ b/src/knx/core/qknxbytearray.h
@@ -92,7 +92,10 @@ public:
void resize(int size);
inline quint8 at(int i) const { return m_bytes.at(i); }
- inline void set(int i, quint8 value) { m_bytes[i] = value; }
+ inline void set(int i, quint8 value) {
+ Q_ASSERT(i >= 0 && i < size());
+ m_bytes[i] = value;
+ }
inline void setValue(int i, quint8 value)
{
diff --git a/src/knx/netip/netip.pri b/src/knx/netip/netip.pri
index 88e2d58..4a154ab 100644
--- a/src/knx/netip/netip.pri
+++ b/src/knx/netip/netip.pri
@@ -96,6 +96,7 @@ SOURCES += $$PWD/qknxnetip.cpp \
$$PWD/qknxnetipsearchresponse.cpp \
$$PWD/qknxnetipserverdescriptionagent.cpp \
$$PWD/qknxnetipserverdiscoveryagent.cpp \
+ $$PWD/qknxnetipserverdiscoveryagent_p.cpp \
$$PWD/qknxnetipserverinfo.cpp \
$$PWD/qknxnetipservicefamiliesdib.cpp \
$$PWD/qknxnetipstruct.cpp \
diff --git a/src/knx/netip/qknxnetipconnectionheader.cpp b/src/knx/netip/qknxnetipconnectionheader.cpp
index 4bf2859..e571e43 100644
--- a/src/knx/netip/qknxnetipconnectionheader.cpp
+++ b/src/knx/netip/qknxnetipconnectionheader.cpp
@@ -237,7 +237,7 @@ QKnxNetIpConnectionHeader QKnxNetIpConnectionHeader::fromBytes(const QKnxByteArr
if (availableSize < 4 && availableSize < totalSize)
return {}; // header might be corrupted
- QKnxNetIpConnectionHeader hdr{ bytes.at(index + 1), bytes.at(index + 2), bytes.at(index + 3) };
+ QKnxNetIpConnectionHeader hdr { bytes.at(index + 1), bytes.at(index + 2), bytes.at(index + 3) };
if (totalSize > 4)
hdr.setConnectionTypeSpecificHeaderItems(bytes.mid(index + 4, totalSize - 4));
return hdr;
diff --git a/src/knx/netip/qknxnetiproutingindication.cpp b/src/knx/netip/qknxnetiproutingindication.cpp
index d84e732..43a1758 100644
--- a/src/knx/netip/qknxnetiproutingindication.cpp
+++ b/src/knx/netip/qknxnetiproutingindication.cpp
@@ -156,7 +156,7 @@ QKnxNetIpRoutingIndicationProxy::Builder QKnxNetIpRoutingIndicationProxy::builde
\code
QKnxLinkLayerFrame linkFrame = // create a link frame ....;
auto netIpframe = QKnxNetIpRoutingIndicationProxy::builder()
- .setLinkLayerFrame(linkFrame)
+ .setCemi(linkFrame)
.create();
\endcode
diff --git a/src/knx/netip/qknxnetipserverdiscoveryagent.cpp b/src/knx/netip/qknxnetipserverdiscoveryagent.cpp
index 30c3d1d..d00fd74 100644
--- a/src/knx/netip/qknxnetipserverdiscoveryagent.cpp
+++ b/src/knx/netip/qknxnetipserverdiscoveryagent.cpp
@@ -119,6 +119,8 @@ QT_BEGIN_NAMESPACE
A network error occurred.
\value NotIPv4
The network protocol used is not IPv4.
+ \value Timeout
+ A timeout occurred while waiting for the description response.
\value Unknown
An unknown error occurred.
*/
@@ -181,288 +183,12 @@ QT_BEGIN_NAMESPACE
\a state.
*/
-QKnxNetIpServerDiscoveryAgentPrivate::QKnxNetIpServerDiscoveryAgentPrivate(const QHostAddress &addr,
- quint16 prt)
- : port(prt)
- , address(addr)
-{}
-
-namespace QKnxPrivate
-{
- static void clearSocket(QUdpSocket **socket)
- {
- if (*socket) {
- (*socket)->disconnect();
- (*socket)->deleteLater();
- (*socket) = nullptr;
- }
- }
-}
-
-void QKnxNetIpServerDiscoveryAgentPrivate::setupSocket()
-{
- usedPort = port;
- usedAddress = address;
- QKnxPrivate::clearSocket(&socket);
-
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- socket = new QUdpSocket(q);
- socket->setSocketOption(QUdpSocket::SocketOption::MulticastTtlOption, ttl);
-
- QObject::connect(socket, &QUdpSocket::stateChanged, [&](QUdpSocket::SocketState s) {
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- switch (s) {
- case QUdpSocket::BoundState:
- setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Running);
-
- if (type == QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast) {
- QNetworkInterface mni;
- const auto interfaces = QNetworkInterface::allInterfaces();
- for (const auto &iface : interfaces) {
- if (!iface.flags().testFlag(QNetworkInterface::CanMulticast))
- continue;
-
- const auto entries = iface.addressEntries();
- for (const auto &entry : entries) {
- auto ip = entry.ip();
- if (ip.protocol() != QAbstractSocket::NetworkLayerProtocol::IPv4Protocol)
- continue;
- if (ip != address)
- continue;
- mni = iface;
- break;
- }
- }
-
- if (socket->joinMulticastGroup(multicastAddress, mni)) {
- usedPort = multicastPort;
- usedAddress = multicastAddress;
- } else {
- setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error::Network,
- QKnxNetIpServerDiscoveryAgent::tr("Could not join multicast group."));
- q->stop();
- }
- } else {
- usedPort = socket->localPort();
- usedAddress = socket->localAddress();
- }
-
- if (q->state() == QKnxNetIpServerDiscoveryAgent::State::Running) {
- servers.clear();
-
- const QFlags<QKnxNetIpServerDiscoveryAgent::DiscoveryMode> flags(discoveryMode);
- if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1)) {
- auto frame = QKnxNetIpSearchRequestProxy::builder()
- .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
- .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
- .setPort(nat ? quint16(0u) : usedPort).create()
- ).create();
- socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
- multicastPort);
- }
-
- if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV2)) {
- auto frame = QKnxNetIpSearchRequestProxy::extendedBuilder()
- .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
- .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
- .setPort(nat ? quint16(0u) : usedPort).create()
- )
- .setExtendedParameters(srps).create();
- socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
- multicastPort);
- }
-
- setupAndStartReceiveTimer();
- setupAndStartFrequencyTimer();
- }
- break;
- default:
- break;
- }
- });
-
- using overload = void (QUdpSocket::*)(QUdpSocket::SocketError);
- QObject::connect(socket,
- static_cast<overload>(&QUdpSocket::error), [&](QUdpSocket::SocketError) {
- setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error::Network,
- socket->errorString());
-
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- q->stop();
- });
-
- QObject::connect(socket, &QUdpSocket::readyRead, [&]() {
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- while (socket->hasPendingDatagrams()) {
- if (q->state() != QKnxNetIpServerDiscoveryAgent::State::Running)
- break;
-
- auto datagram = socket->receiveDatagram();
- auto data = QKnxByteArray::fromByteArray(datagram.data());
- const auto header = QKnxNetIpFrameHeader::fromBytes(data, 0);
- if (!header.isValid())
- continue;
-
- if (header.serviceType() != QKnxNetIp::ServiceType::SearchResponse &&
- header.serviceType() != QKnxNetIp::ServiceType::ExtendedSearchResponse) {
- continue;
- }
-
- auto frame = QKnxNetIpFrame::fromBytes(data);
- auto response = QKnxNetIpSearchResponseProxy(frame);
- if (!response.isValid())
- continue;
-
- const QFlags<QKnxNetIpServerDiscoveryAgent::DiscoveryMode> flags(discoveryMode);
- if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1)
- && !response.isExtended()) {
- setAndEmitDeviceDiscovered({
- (nat ? QKnxNetIpHpaiProxy::builder()
- .setHostAddress(datagram.senderAddress())
- .setPort(datagram.senderPort()).create()
- : response.controlEndpoint()
- ), response.deviceHardware(), response.supportedFamilies()
- });
- }
-
- if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV2)
- && response.isExtended()) {
- const auto optionalDibs = response.optionalDibs();
- setAndEmitDeviceDiscovered({
- (nat ? QKnxNetIpHpaiProxy::builder()
- .setHostAddress(datagram.senderAddress())
- .setPort(datagram.senderPort()).create()
- : response.controlEndpoint()
- ), response.deviceHardware(), response.supportedFamilies(),
- [&optionalDibs]() -> QKnxNetIpDib {
- for (const auto &dib : qAsConst(optionalDibs)) {
- if (dib.code() == QKnxNetIp::DescriptionType::TunnelingInfo)
- return dib;
- }
- return {};
- }(),
- [&optionalDibs]() -> QKnxNetIpDib {
- for (const auto &dib : qAsConst(optionalDibs)) {
- if (dib.code() == QKnxNetIp::DescriptionType::ExtendedDeviceInfo)
- return dib;
- }
- return {};
- }()
- });
- }
- }
- });
-}
-
-namespace QKnxPrivate
-{
- static void clearTimer(QTimer **timer)
- {
- if (*timer) {
- (*timer)->stop();
- (*timer)->disconnect();
- (*timer)->deleteLater();
- (*timer) = nullptr;
- }
- }
-}
-
-void QKnxNetIpServerDiscoveryAgentPrivate::setupAndStartReceiveTimer()
-{
- Q_Q(QKnxNetIpServerDiscoveryAgent);
-
- QKnxPrivate::clearTimer(&receiveTimer);
- if (timeout >= 0) {
- receiveTimer = new QTimer(q);
- receiveTimer->setSingleShot(true);
- receiveTimer->start(timeout);
- QObject::connect(receiveTimer, &QTimer::timeout, q, &QKnxNetIpServerDiscoveryAgent::stop);
- }
-}
-
-void QKnxNetIpServerDiscoveryAgentPrivate::setupAndStartFrequencyTimer()
-{
- Q_Q(QKnxNetIpServerDiscoveryAgent);
-
- QKnxPrivate::clearTimer(&frequencyTimer);
- if (frequency > 0) {
- frequencyTimer = new QTimer(q);
- frequencyTimer->setSingleShot(false);
- frequencyTimer->start(60000 / frequency);
-
- QObject::connect(frequencyTimer, &QTimer::timeout, [&]() {
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- if (q->state() == QKnxNetIpServerDiscoveryAgent::State::Running) {
- servers.clear();
-
- const QFlags<QKnxNetIpServerDiscoveryAgent::DiscoveryMode> flags(discoveryMode);
- if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1)) {
- auto frame = QKnxNetIpSearchRequestProxy::builder()
- .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
- .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
- .setPort(nat ? quint16(0u) : usedPort).create()
- ).create();
- socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
- multicastPort);
- }
-
- if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV2)) {
- auto frame = QKnxNetIpSearchRequestProxy::extendedBuilder()
- .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
- .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
- .setPort(nat ? quint16(0u) : usedPort).create()
- )
- .setExtendedParameters(srps).create();
- socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
- multicastPort);
- }
- }
- });
- }
-}
-
-void QKnxNetIpServerDiscoveryAgentPrivate::setAndEmitStateChanged(
- QKnxNetIpServerDiscoveryAgent::State newState)
-{
- state = newState;
-
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- emit q->stateChanged(newState);
-
- if (state == QKnxNetIpServerDiscoveryAgent::State::Running)
- emit q->started();
- else if (state == QKnxNetIpServerDiscoveryAgent::State::NotRunning)
- emit q->finished();
-}
-
-void QKnxNetIpServerDiscoveryAgentPrivate::setAndEmitDeviceDiscovered(
- const QKnxNetIpServerInfo &discoveryInfo)
-{
- servers.append(discoveryInfo);
-
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- emit q->deviceDiscovered(discoveryInfo);
-}
-
-void QKnxNetIpServerDiscoveryAgentPrivate::setAndEmitErrorOccurred(
- QKnxNetIpServerDiscoveryAgent::Error newError, const QString &message)
-{
- error = newError;
- errorString = message;
-
- Q_Q(QKnxNetIpServerDiscoveryAgent);
- emit q->errorOccurred(error, errorString);
-}
-
-
-// -- QKnxNetIpServerDiscoveryAgent
-
/*!
Creates a KNXnet/IP server discovery agent with the parent \a parent.
*/
QKnxNetIpServerDiscoveryAgent::QKnxNetIpServerDiscoveryAgent(QObject *parent)
- : QKnxNetIpServerDiscoveryAgent(QHostAddress(QHostAddress::AnyIPv4), 0u, parent)
+ : QKnxNetIpServerDiscoveryAgent(QHostAddress(QHostAddress::Null), 0U, parent)
{}
/*!
@@ -470,7 +196,7 @@ QKnxNetIpServerDiscoveryAgent::QKnxNetIpServerDiscoveryAgent(QObject *parent)
*/
QKnxNetIpServerDiscoveryAgent::~QKnxNetIpServerDiscoveryAgent()
{
- stop();
+ d_func()->stop();
}
/*!
@@ -479,7 +205,7 @@ QKnxNetIpServerDiscoveryAgent::~QKnxNetIpServerDiscoveryAgent()
*/
QKnxNetIpServerDiscoveryAgent::QKnxNetIpServerDiscoveryAgent(const QHostAddress &localAddress,
QObject *parent)
- : QKnxNetIpServerDiscoveryAgent(localAddress, 0u, parent)
+ : QKnxNetIpServerDiscoveryAgent(localAddress, 0U, parent)
{}
/*!
@@ -500,8 +226,7 @@ QKnxNetIpServerDiscoveryAgent::QKnxNetIpServerDiscoveryAgent(const QHostAddress
*/
QKnxNetIpServerDiscoveryAgent::State QKnxNetIpServerDiscoveryAgent::state() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->state;
+ return d_func()->state;
}
/*!
@@ -509,8 +234,7 @@ QKnxNetIpServerDiscoveryAgent::State QKnxNetIpServerDiscoveryAgent::state() cons
*/
QKnxNetIpServerDiscoveryAgent::Error QKnxNetIpServerDiscoveryAgent::error() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->error;
+ return d_func()->error;
}
/*!
@@ -518,8 +242,7 @@ QKnxNetIpServerDiscoveryAgent::Error QKnxNetIpServerDiscoveryAgent::error() cons
*/
QString QKnxNetIpServerDiscoveryAgent::errorString() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->errorString;
+ return d_func()->errorString;
}
/*!
@@ -527,8 +250,7 @@ QString QKnxNetIpServerDiscoveryAgent::errorString() const
*/
QVector<QKnxNetIpServerInfo> QKnxNetIpServerDiscoveryAgent::discoveredServers() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->servers;
+ return d_func()->servers;
}
/*!
@@ -567,7 +289,8 @@ QHostAddress QKnxNetIpServerDiscoveryAgent::localAddress() const
}
/*!
- Sets the host address of a discovery agent to \a address.
+ Sets the host address of a discovery agent to \a address. To unset the local
+ address use \l QHostAddress::Null.
\note If the address changes during discovery, the new address will not be
used until the next run.
@@ -587,8 +310,7 @@ void QKnxNetIpServerDiscoveryAgent::setLocalAddress(const QHostAddress &address)
*/
int QKnxNetIpServerDiscoveryAgent::timeout() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->timeout;
+ return d_func()->timeout;
}
/*!
@@ -604,7 +326,6 @@ void QKnxNetIpServerDiscoveryAgent::setTimeout(int msec)
{
Q_D(QKnxNetIpServerDiscoveryAgent);
d->timeout = msec;
- d->setupAndStartReceiveTimer();
}
/*!
@@ -615,8 +336,7 @@ void QKnxNetIpServerDiscoveryAgent::setTimeout(int msec)
*/
int QKnxNetIpServerDiscoveryAgent::searchFrequency() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->frequency;
+ return d_func()->frequency;
}
/*!
@@ -641,8 +361,7 @@ void QKnxNetIpServerDiscoveryAgent::setSearchFrequency(int timesPerMinute)
*/
bool QKnxNetIpServerDiscoveryAgent::natAware() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->nat;
+ return d_func()->nat;
}
/*!
@@ -666,8 +385,7 @@ void QKnxNetIpServerDiscoveryAgent::setNatAware(bool useNat)
*/
quint8 QKnxNetIpServerDiscoveryAgent::multicastTtl() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->ttl;
+ return d_func()->ttl;
}
/*!
@@ -687,8 +405,7 @@ void QKnxNetIpServerDiscoveryAgent::setMulticastTtl(quint8 ttl)
*/
QKnxNetIpServerDiscoveryAgent::ResponseType QKnxNetIpServerDiscoveryAgent::responseType() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->type;
+ return d_func()->type;
}
/*!
@@ -709,8 +426,7 @@ void QKnxNetIpServerDiscoveryAgent::setResponseType(QKnxNetIpServerDiscoveryAgen
*/
QKnxNetIpServerDiscoveryAgent::DiscoveryModes QKnxNetIpServerDiscoveryAgent::discoveryMode() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->discoveryMode;
+ return d_func()->mode;
}
/*!
@@ -724,18 +440,18 @@ void QKnxNetIpServerDiscoveryAgent::setDiscoveryMode(QKnxNetIpServerDiscoveryAge
{
Q_D(QKnxNetIpServerDiscoveryAgent);
if (d->state == QKnxNetIpServerDiscoveryAgent::State::NotRunning)
- d->discoveryMode = mode;
+ d->mode = mode;
}
/*!
\since 5.12
+
Returns the search request parameter (SRP) objects used in an
\l {QKnxNetIpServerDiscoveryAgent::CoreV2} {extended search request}.
*/
QVector<QKnxNetIpSrp> QKnxNetIpServerDiscoveryAgent::extendedSearchParameters() const
{
- Q_D(const QKnxNetIpServerDiscoveryAgent);
- return d->srps;
+ return d_func()->srps;
}
/*!
@@ -752,8 +468,7 @@ QVector<QKnxNetIpSrp> QKnxNetIpServerDiscoveryAgent::extendedSearchParameters()
*/
void QKnxNetIpServerDiscoveryAgent::setExtendedSearchParameters(const QVector<QKnxNetIpSrp> &srps)
{
- Q_D(QKnxNetIpServerDiscoveryAgent);
- d->srps = srps;
+ d_func()->srps = srps;
}
/*!
@@ -761,26 +476,7 @@ void QKnxNetIpServerDiscoveryAgent::setExtendedSearchParameters(const QVector<QK
*/
void QKnxNetIpServerDiscoveryAgent::start()
{
- Q_D(QKnxNetIpServerDiscoveryAgent);
-
- if (d->state != QKnxNetIpServerDiscoveryAgent::State::NotRunning)
- return;
-
- auto isIPv4 = true;
- d->address.toIPv4Address(&isIPv4);
- if (isIPv4) {
- d->setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Starting);
-
- d->setupSocket();
- if (d->type == QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast) {
- d->socket->bind(QHostAddress::AnyIPv4, d->multicastPort, QUdpSocket::ShareAddress
- | QAbstractSocket::ReuseAddressHint);
- } else {
- d->socket->bind(d->address, d->port);
- }
- } else {
- d->setAndEmitErrorOccurred(Error::NotIPv4, tr("Only IPv4 local address supported."));
- }
+ d_func()->start();
}
/*!
@@ -791,32 +487,37 @@ void QKnxNetIpServerDiscoveryAgent::start()
void QKnxNetIpServerDiscoveryAgent::start(int timeout)
{
d_func()->timeout = timeout;
- start();
+ d_func()->start();
}
/*!
- Stops a server discovery agent.
+ Starts a server discovery agent with the network interfaces specified by
+ the list of local host \a addresses.
+
+ \note Does not emit the errorOccurred signal.
*/
-void QKnxNetIpServerDiscoveryAgent::stop()
+void QKnxNetIpServerDiscoveryAgent::start(const QVector<QHostAddress> &addresses)
{
- Q_D(QKnxNetIpServerDiscoveryAgent);
-
- if (d->state == State::Stopping || d->state == State::NotRunning)
- return;
-
- d->setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Stopping);
+ d_func()->start(addresses);
+}
- if (d->type == QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast
- && d->socket->state() == QUdpSocket::BoundState) {
- d->socket->leaveMulticastGroup(d->multicastAddress);
- }
- d->socket->close();
+/*!
+ Starts a server discovery agent with the network interfaces specified by
+ the list of interface types \a types.
- QKnxPrivate::clearSocket(&(d->socket));
- QKnxPrivate::clearTimer(&(d->receiveTimer));
- QKnxPrivate::clearTimer(&(d->frequencyTimer));
+ \note Does not emit the errorOccurred signal.
+*/
+void QKnxNetIpServerDiscoveryAgent::start(QKnxNetIpServerDiscoveryAgent::InterfaceTypes types)
+{
+ d_func()->start(types);
+}
- d->setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::NotRunning);
+/*!
+ Stops a server discovery agent.
+*/
+void QKnxNetIpServerDiscoveryAgent::stop()
+{
+ d_func()->stop();
}
/*!
diff --git a/src/knx/netip/qknxnetipserverdiscoveryagent.h b/src/knx/netip/qknxnetipserverdiscoveryagent.h
index 0fd0455..b7bdf83 100644
--- a/src/knx/netip/qknxnetipserverdiscoveryagent.h
+++ b/src/knx/netip/qknxnetipserverdiscoveryagent.h
@@ -60,6 +60,7 @@ public:
None,
Network,
NotIPv4,
+ Timeout,
Unknown = 0x80
};
Q_ENUM(Error)
@@ -79,8 +80,17 @@ public:
Q_ENUM(DiscoveryMode)
Q_DECLARE_FLAGS(DiscoveryModes, DiscoveryMode)
+ enum class InterfaceType : quint8
+ {
+ Loopback = 0x01,
+ Ethernet = 0x02,
+ Wifi = 0x04
+ };
+ Q_ENUM(InterfaceType)
+ Q_DECLARE_FLAGS(InterfaceTypes, InterfaceType)
+
QKnxNetIpServerDiscoveryAgent(QObject *parent = nullptr);
- ~QKnxNetIpServerDiscoveryAgent();
+ ~QKnxNetIpServerDiscoveryAgent() override;
explicit QKnxNetIpServerDiscoveryAgent(const QHostAddress &localAddress,
QObject *parent = nullptr);
@@ -122,9 +132,12 @@ public:
public Q_SLOTS:
void start();
- void start(int timeout);
void stop();
+ void start(int timeout);
+ void start(const QVector<QHostAddress> &localAddresses);
+ void start(QKnxNetIpServerDiscoveryAgent::InterfaceTypes types);
+
Q_SIGNALS:
void started();
void finished();
@@ -137,6 +150,7 @@ private:
QKnxNetIpServerDiscoveryAgent(QKnxNetIpServerDiscoveryAgentPrivate &dd, QObject *parent);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QKnxNetIpServerDiscoveryAgent::DiscoveryModes)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QKnxNetIpServerDiscoveryAgent::InterfaceTypes)
QT_END_NAMESPACE
diff --git a/src/knx/netip/qknxnetipserverdiscoveryagent_p.cpp b/src/knx/netip/qknxnetipserverdiscoveryagent_p.cpp
new file mode 100644
index 0000000..44e7bb5
--- /dev/null
+++ b/src/knx/netip/qknxnetipserverdiscoveryagent_p.cpp
@@ -0,0 +1,684 @@
+/******************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtKnx module.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+
+#include "qknxnetipserverdiscoveryagent.h"
+#include "qknxnetipserverdiscoveryagent_p.h"
+
+#include <QtCore/qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QKnxPrivate
+{
+ static void clearSocket(QUdpSocket **socket)
+ {
+ if (*socket) {
+ (*socket)->disconnect();
+ (*socket)->deleteLater();
+ (*socket) = nullptr;
+ }
+ }
+
+ static void clearTimer(QTimer **timer)
+ {
+ if (*timer) {
+ (*timer)->stop();
+ (*timer)->disconnect();
+ (*timer)->deleteLater();
+ (*timer) = nullptr;
+ }
+ }
+
+ static QVector<Adapter> adaptersForAddresses(const QVector<QHostAddress> addresses)
+ {
+ QVector<Adapter> adapters;
+ auto all = QNetworkInterface::allInterfaces();
+ for (const auto &iface : all) {
+ const auto flags = iface.flags();
+ if (!flags.testFlag(QNetworkInterface::IsUp)
+ && !flags.testFlag(QNetworkInterface::IsRunning)
+ && !flags.testFlag(QNetworkInterface::CanMulticast)) continue;
+
+ const auto type = iface.type();
+ if (type != QNetworkInterface::Wifi
+ && type != QNetworkInterface::Loopback
+ && type != QNetworkInterface::Ethernet) continue;
+
+ const auto entries = iface.addressEntries();
+ for (const auto &entry : entries) {
+ const auto address = entry.ip();
+ if (address.protocol() != QAbstractSocket::IPv4Protocol)
+ continue;
+ if (!addresses.contains(address))
+ continue;
+ adapters.append({ address, iface });
+ break;
+ }
+ }
+ return adapters;
+ }
+}
+
+Discoverer::Discoverer(const QHostAddress &address, const QNetworkInterface iface, const DiscovererConfig &c)
+ : QObject(nullptr)
+ , m_address(address)
+ , m_iface(iface)
+ , m_config(c)
+{}
+
+Discoverer::~Discoverer()
+{
+ finish();
+}
+
+void Discoverer::start()
+{
+ if (m_state != QKnxNetIpServerDiscoveryAgent::State::NotRunning)
+ return;
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Starting);
+
+ auto isIPv4 = true;
+ m_address.toIPv4Address(&isIPv4);
+ if (!isIPv4) {
+ emit errorOccurred(QKnxNetIpServerDiscoveryAgent::Error::NotIPv4,
+ QKnxNetIpServerDiscoveryAgent::tr("Only IPv4 local address supported."));
+ return finish();
+ }
+
+ m_socket = new QUdpSocket;
+ connect(m_socket, &QUdpSocket::readyRead, this, &Discoverer::onReadyRead);
+ using overload = void (QUdpSocket::*)(QUdpSocket::SocketError);
+ connect(m_socket, static_cast<overload>(&QUdpSocket::error), this, &Discoverer::onError);
+
+ bool bound = m_socket->bind(m_config.Multicast ? QHostAddress::AnyIPv4
+ : m_address,
+ m_config.Multicast ? 3671 : 0,
+ QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
+ if (!bound)
+ return finish();
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Running);
+
+ if (m_config.Multicast) {
+ m_socket->setMulticastInterface(m_iface);
+ if (!m_socket->joinMulticastGroup(m_multicast, m_iface)) {
+ emit errorOccurred(QKnxNetIpServerDiscoveryAgent::Error::Network,
+ QKnxNetIpServerDiscoveryAgent::tr("Could not join multicast group."));
+ return finish();
+ }
+ m_socket->setSocketOption(QUdpSocket::SocketOption::MulticastTtlOption, m_config.Ttl);
+ }
+
+ m_timer = new QTimer;
+ m_timer->setSingleShot(true);
+ connect(m_timer, &QTimer::timeout, this, &Discoverer::onTimeout);
+
+ if (m_config.DiscoveryCoreV1) {
+ const auto frame = QKnxNetIpSearchRequestProxy::builder()
+ .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::Builder()
+ .setPort(m_config.Nat ? 0 : (m_config.Multicast ? 3671 : m_socket->localPort()))
+ .setHostAddress(m_config.Nat ? QHostAddress::AnyIPv4
+ : (m_config.Multicast ? m_multicast : m_address))
+ .create())
+ .create();
+
+ if (frame.isValid())
+ m_socket->writeDatagram(frame.bytes().toByteArray(), m_multicast, 3671);
+ }
+
+ if (m_config.DiscoveryCoreV2) {
+ const auto frame = QKnxNetIpSearchRequestProxy::extendedBuilder()
+ .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::Builder()
+ .setPort(m_config.Nat ? 0 : (m_config.Multicast ? 3671 : m_socket->localPort()))
+ .setHostAddress(m_config.Nat ? QHostAddress::AnyIPv4
+ : (m_config.Multicast ? m_multicast : m_address))
+ .create())
+ .setExtendedParameters(m_config.ExtendedSearchParameters)
+ .create();
+ if (frame.isValid())
+ m_socket->writeDatagram(frame.bytes().toByteArray(), m_multicast, 3671);
+ }
+
+ m_timer->start(m_config.Timeout);
+}
+
+void Discoverer::finish()
+{
+ if (m_state == QKnxNetIpServerDiscoveryAgent::State::Stopping
+ || m_state == QKnxNetIpServerDiscoveryAgent::State::NotRunning) {
+ return;
+ }
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Stopping);
+
+ QKnxPrivate::clearTimer(&m_timer);
+
+ if (m_socket) {
+ if (m_config.Multicast && m_socket->state() == QUdpSocket::BoundState) {
+ m_socket->setMulticastInterface({});
+ m_socket->leaveMulticastGroup(m_multicast, m_iface);
+ }
+ QKnxPrivate::clearSocket(&m_socket);
+ }
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::NotRunning);
+}
+
+void Discoverer::onTimeout()
+{
+ if (m_devices.isEmpty())
+ emit timeout();
+ finish();
+}
+
+void Discoverer::onReadyRead()
+{
+ while (m_socket->hasPendingDatagrams()) {
+ if (m_state != QKnxNetIpServerDiscoveryAgent::State::Running)
+ break;
+
+ const auto datagram = m_socket->receiveDatagram();
+ const auto data = QKnxByteArray::fromByteArray(datagram.data());
+ const auto header = QKnxNetIpFrameHeader::fromBytes(data, 0);
+ if (!header.isValid())
+ continue;
+
+ if (header.serviceType() != QKnxNetIp::ServiceType::SearchResponse
+ && header.serviceType() != QKnxNetIp::ServiceType::ExtendedSearchResponse) {
+ continue;
+ }
+
+ const auto frame = QKnxNetIpFrame::fromBytes(data);
+ const auto proxy = QKnxNetIpSearchResponseProxy(frame);
+ if (!proxy.isValid())
+ continue;
+
+ if (m_config.DiscoveryCoreV1 && !proxy.isExtended()) {
+ emit deviceDiscovered(
+ {
+ (m_config.Nat ? QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(datagram.senderAddress())
+ .setPort(datagram.senderPort()).create()
+ : proxy.controlEndpoint()),
+ proxy.deviceHardware(),
+ proxy.supportedFamilies(),
+ m_address, m_iface
+ }
+ );
+ }
+
+ if (m_config.DiscoveryCoreV2 && proxy.isExtended()) {
+ const auto optionalDibs = proxy.optionalDibs();
+ emit deviceDiscovered(
+ {
+ (m_config.Nat ? QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(datagram.senderAddress())
+ .setPort(datagram.senderPort()).create()
+ : proxy.controlEndpoint()),
+ proxy.deviceHardware(),
+ proxy.supportedFamilies(),
+ m_address, m_iface,
+ [&optionalDibs]() -> QKnxNetIpDib {
+ for (const auto &dib : qAsConst(optionalDibs)) {
+ if (dib.code() == QKnxNetIp::DescriptionType::TunnelingInfo)
+ return dib;
+ }
+ return {};
+ }(),
+ [&optionalDibs]() -> QKnxNetIpDib {
+ for (const auto &dib : qAsConst(optionalDibs)) {
+ if (dib.code() == QKnxNetIp::DescriptionType::ExtendedDeviceInfo)
+ return dib;
+ }
+ return {};
+ }()
+ }
+ );
+ }
+ }
+}
+
+void Discoverer::onError(QUdpSocket::SocketError /* error */)
+{
+ emit errorOccurred(QKnxNetIpServerDiscoveryAgent::Error::Network,
+ m_socket ? m_socket->errorString()
+ : QKnxNetIpServerDiscoveryAgent::tr("Unknown socket error happened.")
+ );
+ finish();
+}
+
+void Discoverer::setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State state)
+{
+ m_state = state;
+ emit stateChanged(m_state);
+
+ if (m_state == QKnxNetIpServerDiscoveryAgent::State::Starting)
+ emit started();
+ if (m_state == QKnxNetIpServerDiscoveryAgent::State::Stopping)
+ emit finished(this);
+}
+
+QKnxNetIpServerDiscoveryAgentPrivate::QKnxNetIpServerDiscoveryAgentPrivate(const QHostAddress &addr,
+ quint16 prt)
+ : port(prt)
+ , address(addr)
+{}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::setupSocket()
+{
+ usedPort = port;
+ usedAddress = address;
+ QKnxPrivate::clearSocket(&socket);
+
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ socket = new QUdpSocket(q);
+
+ adapter = QKnxPrivate::adaptersForAddresses(QVector<QHostAddress> { address }).value(0);
+ QObject::connect(socket, &QUdpSocket::stateChanged, q, [&](QUdpSocket::SocketState s) {
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ switch (s) {
+ case QUdpSocket::BoundState:
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Running);
+ socket->setSocketOption(QUdpSocket::SocketOption::MulticastTtlOption, ttl);
+
+ if (type == QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast) {
+ QNetworkInterface mni;
+ const auto interfaces = QNetworkInterface::allInterfaces();
+ for (const auto &iface : interfaces) {
+ if (!iface.flags().testFlag(QNetworkInterface::CanMulticast))
+ continue;
+
+ const auto entries = iface.addressEntries();
+ for (const auto &entry : entries) {
+ auto ip = entry.ip();
+ if (ip.protocol() != QAbstractSocket::NetworkLayerProtocol::IPv4Protocol)
+ continue;
+ if (ip != address)
+ continue;
+ mni = iface;
+ break;
+ }
+ }
+
+ if (mni.isValid())
+ socket->setMulticastInterface(mni);
+
+ if (socket->joinMulticastGroup(multicastAddress, mni)) {
+ usedPort = multicastPort;
+ usedAddress = multicastAddress;
+ } else {
+ setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error::Network,
+ QKnxNetIpServerDiscoveryAgent::tr("Could not join multicast group."));
+ q->stop();
+ }
+ } else {
+ usedPort = socket->localPort();
+ usedAddress = socket->localAddress();
+ }
+
+ if (q->state() == QKnxNetIpServerDiscoveryAgent::State::Running) {
+ servers.clear();
+
+ const QFlags<QKnxNetIpServerDiscoveryAgent::DiscoveryMode> flags(mode);
+ if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1)) {
+ auto frame = QKnxNetIpSearchRequestProxy::builder()
+ .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
+ .setPort(nat ? quint16(0u) : usedPort).create()
+ ).create();
+ socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
+ multicastPort);
+ }
+
+ if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV2)) {
+ auto frame = QKnxNetIpSearchRequestProxy::extendedBuilder()
+ .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
+ .setPort(nat ? quint16(0u) : usedPort).create()
+ )
+ .setExtendedParameters(srps).create();
+ socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
+ multicastPort);
+ }
+
+ setupAndStartReceiveTimer();
+ setupAndStartFrequencyTimer();
+ }
+ break;
+ default:
+ break;
+ }
+ });
+
+ using overload = void (QUdpSocket::*)(QUdpSocket::SocketError);
+ QObject::connect(socket,
+ static_cast<overload>(&QUdpSocket::error), q, [&](QUdpSocket::SocketError) {
+ setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error::Network,
+ socket->errorString());
+
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ q->stop();
+ });
+
+ QObject::connect(socket, &QUdpSocket::readyRead, q, [&]() {
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ while (socket->hasPendingDatagrams()) {
+ if (q->state() != QKnxNetIpServerDiscoveryAgent::State::Running)
+ break;
+
+ auto datagram = socket->receiveDatagram();
+ auto data = QKnxByteArray::fromByteArray(datagram.data());
+ const auto header = QKnxNetIpFrameHeader::fromBytes(data, 0);
+ if (!header.isValid())
+ continue;
+
+ if (header.serviceType() != QKnxNetIp::ServiceType::SearchResponse &&
+ header.serviceType() != QKnxNetIp::ServiceType::ExtendedSearchResponse) {
+ continue;
+ }
+
+ auto frame = QKnxNetIpFrame::fromBytes(data);
+ auto response = QKnxNetIpSearchResponseProxy(frame);
+ if (!response.isValid())
+ continue;
+
+ const QFlags<QKnxNetIpServerDiscoveryAgent::DiscoveryMode> flags(mode);
+ if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1)
+ && !response.isExtended()) {
+ setAndEmitDeviceDiscovered({
+ (nat ? QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(datagram.senderAddress())
+ .setPort(datagram.senderPort()).create()
+ : response.controlEndpoint()
+ ), response.deviceHardware(), response.supportedFamilies(),
+ adapter.address, adapter.iface
+ });
+ }
+
+ if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV2)
+ && response.isExtended()) {
+ const auto optionalDibs = response.optionalDibs();
+ setAndEmitDeviceDiscovered({
+ (nat ? QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(datagram.senderAddress())
+ .setPort(datagram.senderPort()).create()
+ : response.controlEndpoint()
+ ), response.deviceHardware(), response.supportedFamilies(),
+ adapter.address, adapter.iface,
+ [&optionalDibs]() -> QKnxNetIpDib {
+ for (const auto &dib : qAsConst(optionalDibs)) {
+ if (dib.code() == QKnxNetIp::DescriptionType::TunnelingInfo)
+ return dib;
+ }
+ return {};
+ }(),
+ [&optionalDibs]() -> QKnxNetIpDib {
+ for (const auto &dib : qAsConst(optionalDibs)) {
+ if (dib.code() == QKnxNetIp::DescriptionType::ExtendedDeviceInfo)
+ return dib;
+ }
+ return {};
+ }()
+ });
+ }
+ }
+ });
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::setupAndStartReceiveTimer()
+{
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+
+ QKnxPrivate::clearTimer(&receiveTimer);
+ if (timeout >= 0) {
+ receiveTimer = new QTimer(q);
+ receiveTimer->setSingleShot(true);
+ receiveTimer->start(timeout);
+ QObject::connect(receiveTimer, &QTimer::timeout, q, &QKnxNetIpServerDiscoveryAgent::stop);
+ }
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::setupAndStartFrequencyTimer()
+{
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+
+ QKnxPrivate::clearTimer(&frequencyTimer);
+ if (frequency > 0) {
+ frequencyTimer = new QTimer(q);
+ frequencyTimer->setSingleShot(false);
+ frequencyTimer->start(60000 / frequency);
+
+ QObject::connect(frequencyTimer, &QTimer::timeout, q, [&]() {
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ if (q->state() == QKnxNetIpServerDiscoveryAgent::State::Running) {
+ servers.clear();
+
+ const QFlags<QKnxNetIpServerDiscoveryAgent::DiscoveryMode> flags(mode);
+ if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1)) {
+ auto frame = QKnxNetIpSearchRequestProxy::builder()
+ .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
+ .setPort(nat ? quint16(0u) : usedPort).create()
+ ).create();
+ socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
+ multicastPort);
+ }
+
+ if (flags.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV2)) {
+ auto frame = QKnxNetIpSearchRequestProxy::extendedBuilder()
+ .setDiscoveryEndpoint(QKnxNetIpHpaiProxy::builder()
+ .setHostAddress(nat ? QHostAddress::AnyIPv4 : usedAddress)
+ .setPort(nat ? quint16(0u) : usedPort).create()
+ )
+ .setExtendedParameters(srps).create();
+ socket->writeDatagram(frame.bytes().toByteArray(), multicastAddress,
+ multicastPort);
+ }
+ }
+ });
+ }
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::setAndEmitStateChanged(
+ QKnxNetIpServerDiscoveryAgent::State newState)
+{
+ state = newState;
+
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ emit q->stateChanged(newState);
+
+ if (state == QKnxNetIpServerDiscoveryAgent::State::Running)
+ emit q->started();
+ else if (state == QKnxNetIpServerDiscoveryAgent::State::NotRunning)
+ emit q->finished();
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::setAndEmitDeviceDiscovered(
+ const QKnxNetIpServerInfo &discoveryInfo)
+{
+ servers.append(discoveryInfo);
+
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ emit q->deviceDiscovered(discoveryInfo);
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::setAndEmitErrorOccurred(
+ QKnxNetIpServerDiscoveryAgent::Error newError, const QString &message)
+{
+ error = newError;
+ errorString = message;
+
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ emit q->errorOccurred(error, errorString);
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::start()
+{
+ if (state != QKnxNetIpServerDiscoveryAgent::State::NotRunning)
+ return;
+
+ if (address.isNull())
+ address = QHostAddress(QHostAddress::AnyIPv4);
+
+ auto isIPv4 = true;
+ address.toIPv4Address(&isIPv4);
+ if (isIPv4) {
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Starting);
+ setupSocket();
+ if (type == QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast) {
+ socket->bind(QHostAddress::AnyIPv4, multicastPort, QUdpSocket::ShareAddress
+ | QAbstractSocket::ReuseAddressHint);
+ } else {
+ socket->bind(address, port);
+ }
+ } else {
+ setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error::NotIPv4,
+ QKnxNetIpServerDiscoveryAgent::tr("Only IPv4 local address supported."));
+ }
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::start(const QVector<Adapter> &adapters)
+{
+ if (state != QKnxNetIpServerDiscoveryAgent::State::NotRunning)
+ return;
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Starting);
+
+ if (adapters.isEmpty())
+ return stop();
+
+ Q_Q(QKnxNetIpServerDiscoveryAgent);
+ const QFlags<QKnxNetIpServerDiscoveryAgent::ResponseType> rtype(type);
+ const QFlags<QKnxNetIpServerDiscoveryAgent::DiscoveryMode> dmode(mode);
+ const DiscovererConfig config {
+ ttl,
+ timeout,
+ nat,
+ rtype.testFlag(QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast),
+ dmode.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1),
+ dmode.testFlag(QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV2),
+ srps
+ };
+
+ bool connectError = (adapters.count() == 1);
+ for (const auto &adapter : adapters) {
+ auto discoverer = new Discoverer(adapter.address, adapter.iface, config);
+ discoveries.append(discoverer);
+
+ auto thread = new QThread;
+ discoverer->moveToThread(thread);
+ QObject::connect(thread, &QThread::started, discoverer, &Discoverer::start);
+ QObject::connect(thread, &QThread::finished, discoverer, &Discoverer::deleteLater);
+
+ QObject::connect(thread, &QThread::started, discoverer, &Discoverer::start);
+ QObject::connect(thread, &QThread::finished, discoverer, &Discoverer::finish);
+
+ QObject::connect(discoverer, &Discoverer::finished, q, [&](Discoverer *ds) {
+ discoveries.removeAll(ds);
+ if (discoveries.isEmpty())
+ stop();
+ });
+ QObject::connect(discoverer, &Discoverer::finished, thread, &QThread::quit);
+ QObject::connect(discoverer, &Discoverer::deviceDiscovered, q, [&](const QKnxNetIpServerInfo &server) {
+ setAndEmitDeviceDiscovered(server);
+ });
+ if (connectError) {
+ QObject::connect(discoverer, &Discoverer::errorOccurred, q,
+ [&](QKnxNetIpServerDiscoveryAgent::Error error, const QString &errorString) {
+ setAndEmitErrorOccurred(error, errorString);
+ });
+ }
+ thread->start();
+ }
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Running);
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::start(const QVector<QHostAddress> addresses)
+{
+ start(QKnxPrivate::adaptersForAddresses(addresses));
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::start(QKnxNetIpServerDiscoveryAgent::InterfaceTypes types)
+{
+ QVector<Adapter> adapters;
+ auto all = QNetworkInterface::allInterfaces();
+ for (const auto &iface : all) {
+ const auto flags = iface.flags();
+ if (!flags.testFlag(QNetworkInterface::IsUp)
+ && !flags.testFlag(QNetworkInterface::IsRunning)
+ && !flags.testFlag(QNetworkInterface::CanMulticast)) continue;
+
+ const bool wifi = types.testFlag(QKnxNetIpServerDiscoveryAgent::InterfaceType::Wifi);
+ const bool loopback = types.testFlag(QKnxNetIpServerDiscoveryAgent::InterfaceType::Loopback);
+ const bool ethernet = types.testFlag(QKnxNetIpServerDiscoveryAgent::InterfaceType::Ethernet);
+
+ const auto type = iface.type();
+ if (!(wifi && type == QNetworkInterface::Wifi)
+ && !(loopback && type == QNetworkInterface::Loopback)
+ && !(ethernet && type == QNetworkInterface::Ethernet)) continue;
+
+ const auto entries = iface.addressEntries();
+ for (const auto &entry : entries) {
+ const auto address = entry.ip();
+ if (address.protocol() != QAbstractSocket::IPv4Protocol)
+ continue;
+ adapters.append({ address, iface });
+ break;
+ }
+ }
+ start(adapters);
+}
+
+void QKnxNetIpServerDiscoveryAgentPrivate::stop()
+{
+ if (state == QKnxNetIpServerDiscoveryAgent::State::Stopping
+ || state == QKnxNetIpServerDiscoveryAgent::State::NotRunning) {
+ return;
+ }
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::Stopping);
+
+ if (socket) {
+ if (type == QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast
+ && socket->state() == QUdpSocket::BoundState) {
+ socket->leaveMulticastGroup(multicastAddress);
+ }
+ socket->close();
+ }
+
+ QKnxPrivate::clearSocket(&(socket));
+ QKnxPrivate::clearTimer(&(receiveTimer));
+ QKnxPrivate::clearTimer(&(frequencyTimer));
+
+ setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State::NotRunning);
+}
+
+QT_END_NAMESPACE
diff --git a/src/knx/netip/qknxnetipserverdiscoveryagent_p.h b/src/knx/netip/qknxnetipserverdiscoveryagent_p.h
index 21bdcdf..46be5fe 100644
--- a/src/knx/netip/qknxnetipserverdiscoveryagent_p.h
+++ b/src/knx/netip/qknxnetipserverdiscoveryagent_p.h
@@ -47,14 +47,94 @@
#include <QtKnx/qknxnetipsearchrequest.h>
#include <QtKnx/qknxnetipsearchresponse.h>
#include <QtKnx/qknxnetipserverdiscoveryagent.h>
+
#include <QtNetwork/qhostaddress.h>
#include <QtNetwork/qnetworkdatagram.h>
+#include <QtNetwork/qnetworkinterface.h>
#include <QtNetwork/qudpsocket.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
+struct Adapter
+{
+ QHostAddress address;
+ QNetworkInterface iface;
+};
+
+struct DiscovererConfig
+{
+ DiscovererConfig() = default;
+ ~DiscovererConfig() = default;
+
+ DiscovererConfig(int ttl, int timeout, bool nat, bool multicast, bool coreV1, bool coreV2,
+ const QVector<QKnxNetIpSrp> &srps)
+ : Ttl(ttl)
+ , Timeout(timeout)
+ , Nat(nat)
+ , Multicast(multicast)
+ , DiscoveryCoreV1(coreV1)
+ , DiscoveryCoreV2(coreV2)
+ , ExtendedSearchParameters(srps)
+ {}
+
+ int Ttl { 64 };
+ int Timeout { 3000 };
+
+ bool Nat { false };
+ bool Multicast { true };
+
+ bool DiscoveryCoreV1 { true };
+ bool DiscoveryCoreV2 { true };
+
+ QVector<QKnxNetIpSrp> ExtendedSearchParameters;
+};
+
+class Discoverer : public QObject
+{
+ Q_OBJECT
+
+public:
+ Discoverer(const QHostAddress &address, const QNetworkInterface iface, const DiscovererConfig &config);
+ ~Discoverer() override;
+
+public slots:
+ void start();
+ void finish();
+
+signals:
+ void started();
+ void timeout();
+ void finished(Discoverer *iam);
+
+ void stateChanged(QKnxNetIpServerDiscoveryAgent::State state);
+ void errorOccurred(QKnxNetIpServerDiscoveryAgent::Error error, const QString &errorString);
+
+ void deviceDiscovered(const QKnxNetIpServerInfo &discoveryInfo);
+
+private slots:
+ void onTimeout();
+ void onReadyRead();
+ void onError(QUdpSocket::SocketError error);
+
+private:
+ void setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State state);
+
+private:
+ QHostAddress m_address;
+ QNetworkInterface m_iface;
+
+ QTimer *m_timer { nullptr };
+ QUdpSocket *m_socket { nullptr };
+
+ DiscovererConfig m_config;
+ QVector<QByteArray> m_devices;
+
+ QHostAddress m_multicast { QStringLiteral("224.0.23.12") };
+ QKnxNetIpServerDiscoveryAgent::State m_state { QKnxNetIpServerDiscoveryAgent::State::NotRunning };
+};
+
class Q_KNX_EXPORT QKnxNetIpServerDiscoveryAgentPrivate final : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QKnxNetIpServerDiscoveryAgent)
@@ -70,7 +150,13 @@ public:
void setAndEmitStateChanged(QKnxNetIpServerDiscoveryAgent::State newState);
void setAndEmitDeviceDiscovered(const QKnxNetIpServerInfo &discoveryInfo);
- void setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error e, const QString &message);
+ void setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error newError, const QString &message);
+
+ void start();
+ void start(const QVector<Adapter> &adapters);
+ void start(const QVector<QHostAddress> addresses);
+ void start(QKnxNetIpServerDiscoveryAgent::InterfaceTypes types);
+ void stop();
private:
QUdpSocket *socket { nullptr };
@@ -78,12 +164,12 @@ private:
QTimer *frequencyTimer { nullptr };
quint16 port { 0 }, usedPort { 0 };
- QHostAddress address { QHostAddress::AnyIPv4 }, usedAddress;
+ QHostAddress address { QHostAddress::Null }, usedAddress;
const quint16 multicastPort { QKnxNetIp::Constants::DefaultPort };
const QHostAddress multicastAddress { QLatin1String(QKnxNetIp::Constants::MulticastAddress) };
- quint8 ttl { 60 };
+ quint8 ttl { 64 };
bool nat { false };
int frequency { 0 };
int timeout { QKnxNetIp::Timeout::SearchTimeout };
@@ -96,9 +182,12 @@ private:
QKnxNetIpServerDiscoveryAgent::ResponseType
type { QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast };
- QKnxNetIpServerDiscoveryAgent::DiscoveryModes discoveryMode
+ QKnxNetIpServerDiscoveryAgent::DiscoveryModes mode
{ QKnxNetIpServerDiscoveryAgent::DiscoveryMode::CoreV1 };
QVector<QKnxNetIpSrp> srps;
+
+ Adapter adapter;
+ QVector<Discoverer*> discoveries;
};
QT_END_NAMESPACE
diff --git a/src/knx/netip/qknxnetipserverinfo.cpp b/src/knx/netip/qknxnetipserverinfo.cpp
index 31ac706..d8c6b62 100644
--- a/src/knx/netip/qknxnetipserverinfo.cpp
+++ b/src/knx/netip/qknxnetipserverinfo.cpp
@@ -98,7 +98,9 @@ QT_BEGIN_NAMESPACE
*/
QKnxNetIpServerInfo::QKnxNetIpServerInfo()
: d_ptr(new QKnxNetIpServerInfoPrivate)
-{}
+{
+ qRegisterMetaType<QKnxNetIpServerInfo>();
+}
/*!
Deletes a KNXnet/IP server information object.
@@ -254,6 +256,32 @@ QKnxNetIpDib QKnxNetIpServerInfo::extendedHardware() const
}
/*!
+ \since 5.14
+
+ Returns the host address which has been used to discover the KNXnet/IP
+ server hardware.
+
+ \sa QHostAddress
+*/
+QHostAddress QKnxNetIpServerInfo::hostAddress() const
+{
+ return d_ptr->address;
+}
+
+/*!
+ \since 5.14
+
+ Returns the network interface which has been used to discover the KNXnet/IP
+ server hardware.
+
+ \sa QNetworkInterface
+*/
+QNetworkInterface QKnxNetIpServerInfo::networkInterface() const
+{
+ return d_ptr->iinterface;
+}
+
+/*!
Constructs a copy of \a other.
*/
QKnxNetIpServerInfo::QKnxNetIpServerInfo(const QKnxNetIpServerInfo &other)
@@ -321,16 +349,13 @@ void QKnxNetIpServerInfo::swap(QKnxNetIpServerInfo &other) Q_DECL_NOTHROW
d_ptr.swap(other.d_ptr);
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
/*!
\internal
*/
QKnxNetIpServerInfo::QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai, const QKnxNetIpDib &hardware,
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QKnxNetIpDib services)
-#else
- const QKnxNetIpDib &services) // ### Qt6: pass services as const reference
-#endif
: QKnxNetIpServerInfo()
{
d_ptr->hpai = hpai;
@@ -338,17 +363,29 @@ QKnxNetIpServerInfo::QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai, const QKnxNe
d_ptr->services = services;
}
-
/*!
\internal
*/
QKnxNetIpServerInfo::QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai, const QKnxNetIpDib &hardware,
const QKnxNetIpDib &services, const QKnxNetIpDib &tunneling, const QKnxNetIpDib &extHardware)
+ : QKnxNetIpServerInfo(hpai, hardware, services, {}, {}, tunneling, extHardware)
+{}
+
+#endif
+
+/*!
+ \internal
+*/
+QKnxNetIpServerInfo::QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai, const QKnxNetIpDib &hardware,
+ const QKnxNetIpDib &services, const QHostAddress &address, const QNetworkInterface &iinterface,
+ const QKnxNetIpDib &tunneling, const QKnxNetIpDib &extHardware)
: QKnxNetIpServerInfo()
{
d_ptr->hpai = hpai;
d_ptr->hardware = hardware;
d_ptr->services = services;
+ d_ptr->address = address;
+ d_ptr->iinterface = iinterface;
d_ptr->tunnelingInfo = tunneling;
d_ptr->extendedHardware = extHardware;
}
diff --git a/src/knx/netip/qknxnetipserverinfo.h b/src/knx/netip/qknxnetipserverinfo.h
index 772586f..4db9656 100644
--- a/src/knx/netip/qknxnetipserverinfo.h
+++ b/src/knx/netip/qknxnetipserverinfo.h
@@ -39,6 +39,7 @@
#include <QtKnx/qknxnetiptunnelinginfodib.h>
#include <QtNetwork/qhostaddress.h>
+#include <QtNetwork/qnetworkinterface.h>
QT_BEGIN_NAMESPACE
@@ -46,6 +47,7 @@ struct QKnxNetIpServerInfoPrivate;
class Q_KNX_EXPORT QKnxNetIpServerInfo final
{
+ friend class Discoverer;
friend class QKnxNetIpServerDiscoveryAgentPrivate;
friend class QKnxNetIpServerDescriptionAgentPrivate;
@@ -72,6 +74,9 @@ public:
QKnxNetIpDib tunnelingInfo() const;
QKnxNetIpDib extendedHardware() const;
+ QHostAddress hostAddress() const;
+ QNetworkInterface networkInterface() const;
+
QKnxNetIpServerInfo(const QKnxNetIpServerInfo &other);
QKnxNetIpServerInfo &operator=(const QKnxNetIpServerInfo &other);
@@ -84,16 +89,23 @@ public:
void swap(QKnxNetIpServerInfo &other) Q_DECL_NOTHROW;
private:
- QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai, const QKnxNetIpDib &hardware,
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai, const QKnxNetIpDib &hardware,
QKnxNetIpDib services);
-#else
- const QKnxNetIpDib &services);
-#endif
QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai, const QKnxNetIpDib &hardware,
const QKnxNetIpDib &services, const QKnxNetIpDib &tunnelingInfo,
const QKnxNetIpDib &extendedHardware);
+#endif
+
+ QKnxNetIpServerInfo(const QKnxNetIpHpai &hpai,
+ const QKnxNetIpDib &hardware,
+ const QKnxNetIpDib &services,
+ const QHostAddress &hostAddress,
+ const QNetworkInterface &iinterface,
+ const QKnxNetIpDib &tunnelingInfo = {},
+ const QKnxNetIpDib &extendedHardware = {});
+
explicit QKnxNetIpServerInfo(QKnxNetIpServerInfoPrivate &dd);
private:
diff --git a/src/knx/netip/qknxnetipserverinfo_p.h b/src/knx/netip/qknxnetipserverinfo_p.h
index 869d909..ca0fd50 100644
--- a/src/knx/netip/qknxnetipserverinfo_p.h
+++ b/src/knx/netip/qknxnetipserverinfo_p.h
@@ -42,11 +42,15 @@
//
#include <QtCore/qshareddata.h>
+
#include <QtKnx/qtknxglobal.h>
#include <QtKnx/qknxnetipdevicedib.h>
#include <QtKnx/qknxnetiphpai.h>
#include <QtKnx/qknxnetipservicefamiliesdib.h>
+#include <QtNetwork/qhostaddress.h>
+#include <QtNetwork/qnetworkinterface.h>
+
QT_BEGIN_NAMESPACE
struct Q_KNX_EXPORT QKnxNetIpServerInfoPrivate final : public QSharedData
@@ -59,6 +63,8 @@ struct Q_KNX_EXPORT QKnxNetIpServerInfoPrivate final : public QSharedData
QKnxNetIpDib services;
QKnxNetIpDib tunnelingInfo;
QKnxNetIpDib extendedHardware;
+ QHostAddress address;
+ QNetworkInterface iinterface;
};
QT_END_NAMESPACE
diff --git a/src/knx/qknxdevicemanagementframe.cpp b/src/knx/qknxdevicemanagementframe.cpp
index 562dd00..c36c5ca 100644
--- a/src/knx/qknxdevicemanagementframe.cpp
+++ b/src/knx/qknxdevicemanagementframe.cpp
@@ -339,6 +339,7 @@ void QKnxDeviceManagementFrame::setObjectInstance(quint8 instance)
{
if (instance < 1)
return;
+ d_ptr->m_serviceInformation.resize(3);
d_ptr->m_serviceInformation.set(2, instance);
}
@@ -359,8 +360,10 @@ QKnxInterfaceObjectProperty QKnxDeviceManagementFrame::property() const
*/
void QKnxDeviceManagementFrame::setProperty(QKnxInterfaceObjectProperty pid)
{
- if (QKnxInterfaceObjectProperty::isProperty(pid))
+ if (QKnxInterfaceObjectProperty::isProperty(pid)) {
+ d_ptr->m_serviceInformation.resize(4);
d_ptr->m_serviceInformation.set(3, quint8(pid));
+ }
}
/*!
@@ -384,6 +387,8 @@ void QKnxDeviceManagementFrame::setNumberOfElements(quint8 numOfElements)
{
if (numOfElements > 0x0f)
return;
+
+ d_ptr->m_serviceInformation.resize(5);
d_ptr->m_serviceInformation.set(4,
(d_ptr->m_serviceInformation.value(4) & 0x0f) | (numOfElements << 4));
}
@@ -475,8 +480,7 @@ void QKnxDeviceManagementFrame::setError(QKnxNetIpCemiServer::Error error)
switch (messageCode()) {
case MessageCode::PropertyReadConfirmation:
case MessageCode::PropertyWriteConfirmation: {
- if (d_ptr->m_serviceInformation.size() < 7)
- d_ptr->m_serviceInformation.resize(7);
+ d_ptr->m_serviceInformation.resize(7);
d_ptr->m_serviceInformation.set(6, quint8(error));
}
default:
@@ -523,8 +527,7 @@ void QKnxDeviceManagementFrame::setReturnCode(QKnxNetIpCemiServer::ReturnCode co
return;
}
- if (d_ptr->m_serviceInformation.size() < 6)
- d_ptr->m_serviceInformation.resize(6);
+ d_ptr->m_serviceInformation.resize(6);
d_ptr->m_serviceInformation.set(5, quint8(code));
}
diff --git a/src/knx/ssl/qknxsecurekey.cpp b/src/knx/ssl/qknxsecurekey.cpp
index 5aadbf9..8ca21ae 100644
--- a/src/knx/ssl/qknxsecurekey.cpp
+++ b/src/knx/ssl/qknxsecurekey.cpp
@@ -57,9 +57,9 @@ public:
}
#if QT_CONFIG(opensslv11)
- EVP_PKEY *m_evpPKey{ nullptr };
+ EVP_PKEY *m_evpPKey { nullptr };
#endif
- QKnxSecureKey::Type m_type{ QKnxSecureKey::Type::Invalid };
+ QKnxSecureKey::Type m_type { QKnxSecureKey::Type::Invalid };
};
/*!
diff --git a/tests/auto/qknxnetipcri/tst_qknxnetipcri.cpp b/tests/auto/qknxnetipcri/tst_qknxnetipcri.cpp
index c86c3af..2deae37 100644
--- a/tests/auto/qknxnetipcri/tst_qknxnetipcri.cpp
+++ b/tests/auto/qknxnetipcri/tst_qknxnetipcri.cpp
@@ -200,7 +200,7 @@ void tst_QKnxNetIpCri::testAdditionalData()
.create();
frame2 = QKnxNetIpCriProxy::builder()
.setConnectionType(QKnxNetIp::ConnectionType::Tunnel)
- .setAdditionalData(QKnxByteArray{ quint8(QKnxNetIp::TunnelLayer::Link), 0x00 }
+ .setAdditionalData(QKnxByteArray { quint8(QKnxNetIp::TunnelLayer::Link), 0x00 }
+ address.bytes())
.create();
QCOMPARE(frame, frame2);
diff --git a/tests/auto/qknxnetiprouter/tst_qknxnetiprouter.cpp b/tests/auto/qknxnetiprouter/tst_qknxnetiprouter.cpp
index 3474b61..47a002b 100644
--- a/tests/auto/qknxnetiprouter/tst_qknxnetiprouter.cpp
+++ b/tests/auto/qknxnetiprouter/tst_qknxnetiprouter.cpp
@@ -327,7 +327,7 @@ QKnxNetIpFrame dummyRoutingIndication(QKnxAddress dst, quint8 hopCount = 6)
.setMedium(QKnx::MediumType::NetIP)
.createFrame();
return QKnxNetIpRoutingIndicationProxy::builder()
- .setLinkLayerFrame(frame)
+ .setCemi(frame)
.create();
}
diff --git a/tests/auto/qknxtunnelframefactory/tst_qknxtunnelframefactory.cpp b/tests/auto/qknxtunnelframefactory/tst_qknxtunnelframefactory.cpp
index 6a42544..af06c8f 100644
--- a/tests/auto/qknxtunnelframefactory/tst_qknxtunnelframefactory.cpp
+++ b/tests/auto/qknxtunnelframefactory/tst_qknxtunnelframefactory.cpp
@@ -300,7 +300,7 @@ void tst_QKnxLinkLayerFrameBuilder::testMemoryRead()
.create();
QCOMPARE(extctr.destinationAddressType(), QKnxAddress::Type::Individual);
auto byts = extctr.bytes();
- QCOMPARE(extctr.bytes(), QKnxByteArray{0x60});
+ QCOMPARE(extctr.bytes(), QKnxByteArray { 0x60 });
auto frame = QKnxLinkLayerFrame::builder().setControlField(ctrl).setExtendedControlField(extctr)
.setTpdu(tpdu).setDestinationAddress(destination).setSourceAddress(source)