diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-09-05 09:02:02 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-09-05 09:02:03 +0200 |
commit | e4edadd2dcb0a7a20cdcfa7d4b4b2a2415227245 (patch) | |
tree | cd2adefedba016885a44f50ceaac4eeadab7aaef | |
parent | 0e4c4e4ddc707384e44e68c3a77479ba11bf61b1 (diff) | |
parent | df0ba9b97c26901f52769381df3c4cbf1fae9ca6 (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: I573251c84151c29558c1edbbb8c394661f577b63
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) |