diff options
author | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-08-16 09:39:26 +0200 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-08-21 16:35:53 +0200 |
commit | 5e1e8e069c1af260e2fcf26777a5e746cf9ae9c6 (patch) | |
tree | 3349227ba2b437bb3bcefb04c86d888b4636efd2 | |
parent | a8b3aacf2630933b16dc093b9ab8505ead8e25c6 (diff) |
Implement device discovery on all available interfaces
Change-Id: Ifbe8ea3611d08e63751ee714c6cf40044ff37e1b
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
-rw-r--r-- | examples/knx/discoverer/main.cpp | 35 | ||||
-rw-r--r-- | src/knx/netip/qknxnetipserverdiscoveryagent.cpp | 23 | ||||
-rw-r--r-- | src/knx/netip/qknxnetipserverdiscoveryagent.h | 15 | ||||
-rw-r--r-- | src/knx/netip/qknxnetipserverdiscoveryagent_p.cpp | 383 | ||||
-rw-r--r-- | src/knx/netip/qknxnetipserverdiscoveryagent_p.h | 86 | ||||
-rw-r--r-- | src/knx/netip/qknxnetipserverinfo.cpp | 4 | ||||
-rw-r--r-- | src/knx/netip/qknxnetipserverinfo.h | 1 |
7 files changed, 479 insertions, 68 deletions
diff --git a/examples/knx/discoverer/main.cpp b/examples/knx/discoverer/main.cpp index 0e539bc..a2c292b 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,15 +174,17 @@ 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) { diff --git a/src/knx/netip/qknxnetipserverdiscoveryagent.cpp b/src/knx/netip/qknxnetipserverdiscoveryagent.cpp index 4ed44da..d00fd74 100644 --- a/src/knx/netip/qknxnetipserverdiscoveryagent.cpp +++ b/src/knx/netip/qknxnetipserverdiscoveryagent.cpp @@ -326,7 +326,6 @@ void QKnxNetIpServerDiscoveryAgent::setTimeout(int msec) { Q_D(QKnxNetIpServerDiscoveryAgent); d->timeout = msec; - d->setupAndStartReceiveTimer(); } /*! @@ -492,6 +491,28 @@ void QKnxNetIpServerDiscoveryAgent::start(int timeout) } /*! + 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::start(const QVector<QHostAddress> &addresses) +{ + d_func()->start(addresses); +} + +/*! + Starts a server discovery agent with the network interfaces specified by + the list of interface types \a types. + + \note Does not emit the errorOccurred signal. +*/ +void QKnxNetIpServerDiscoveryAgent::start(QKnxNetIpServerDiscoveryAgent::InterfaceTypes types) +{ + d_func()->start(types); +} + +/*! Stops a server discovery agent. */ void QKnxNetIpServerDiscoveryAgent::stop() diff --git a/src/knx/netip/qknxnetipserverdiscoveryagent.h b/src/knx/netip/qknxnetipserverdiscoveryagent.h index 8367628..b7bdf83 100644 --- a/src/knx/netip/qknxnetipserverdiscoveryagent.h +++ b/src/knx/netip/qknxnetipserverdiscoveryagent.h @@ -80,6 +80,15 @@ 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() override; @@ -123,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(); @@ -138,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 index e1365a7..002878c 100644 --- a/src/knx/netip/qknxnetipserverdiscoveryagent_p.cpp +++ b/src/knx/netip/qknxnetipserverdiscoveryagent_p.cpp @@ -30,16 +30,10 @@ #include "qknxnetipserverdiscoveryagent.h" #include "qknxnetipserverdiscoveryagent_p.h" -#include <QtNetwork/qnetworkinterface.h> +#include <QtCore/qthread.h> QT_BEGIN_NAMESPACE -QKnxNetIpServerDiscoveryAgentPrivate::QKnxNetIpServerDiscoveryAgentPrivate(const QHostAddress &addr, - quint16 prt) - : port(prt) - , address(addr) -{} - namespace QKnxPrivate { static void clearSocket(QUdpSocket **socket) @@ -50,8 +44,253 @@ namespace QKnxPrivate (*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_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_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; @@ -61,6 +300,7 @@ void QKnxNetIpServerDiscoveryAgentPrivate::setupSocket() 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) { @@ -177,8 +417,7 @@ void QKnxNetIpServerDiscoveryAgentPrivate::setupSocket() .setHostAddress(datagram.senderAddress()) .setPort(datagram.senderPort()).create() : response.controlEndpoint() - ), response.deviceHardware(), response.supportedFamilies(), - QNetworkInterface::interfaceFromIndex(datagram.interfaceIndex()) + ), response.deviceHardware(), response.supportedFamilies(), adapter.iface }); } @@ -190,8 +429,7 @@ void QKnxNetIpServerDiscoveryAgentPrivate::setupSocket() .setHostAddress(datagram.senderAddress()) .setPort(datagram.senderPort()).create() : response.controlEndpoint() - ), response.deviceHardware(), response.supportedFamilies(), - QNetworkInterface::interfaceFromIndex(datagram.interfaceIndex()), + ), response.deviceHardware(), response.supportedFamilies(), adapter.iface, [&optionalDibs]() -> QKnxNetIpDib { for (const auto &dib : qAsConst(optionalDibs)) { if (dib.code() == QKnxNetIp::DescriptionType::TunnelingInfo) @@ -212,19 +450,6 @@ void QKnxNetIpServerDiscoveryAgentPrivate::setupSocket() }); } -namespace QKnxPrivate -{ - static void clearTimer(QTimer **timer) - { - if (*timer) { - (*timer)->stop(); - (*timer)->disconnect(); - (*timer)->deleteLater(); - (*timer) = nullptr; - } - } -} - void QKnxNetIpServerDiscoveryAgentPrivate::setupAndStartReceiveTimer() { Q_Q(QKnxNetIpServerDiscoveryAgent); @@ -312,21 +537,6 @@ void QKnxNetIpServerDiscoveryAgentPrivate::setAndEmitErrorOccurred( emit q->errorOccurred(error, errorString); } -namespace QKnxPrivate -{ - QString interfaceFromAddress(const QHostAddress &address) - { - auto interfaces = QNetworkInterface::allInterfaces(); - for (const auto &interface : qAsConst(interfaces)) { - auto entries = interface.addressEntries(); - for (const auto &entry : entries) { - if (entry.ip() == address) - return interface.humanReadableName(); - } - } - return QLatin1String("Unknown"); - } -} void QKnxNetIpServerDiscoveryAgentPrivate::start() { if (state != QKnxNetIpServerDiscoveryAgent::State::NotRunning) @@ -343,10 +553,8 @@ void QKnxNetIpServerDiscoveryAgentPrivate::start() if (type == QKnxNetIpServerDiscoveryAgent::ResponseType::Multicast) { socket->bind(QHostAddress::AnyIPv4, multicastPort, QUdpSocket::ShareAddress | QAbstractSocket::ReuseAddressHint); - qDebug() << "Multicast response using iface:" << QKnxPrivate::interfaceFromAddress(address); } else { socket->bind(address, port); - qDebug() << "Unicast response using interface:" << QKnxPrivate::interfaceFromAddress(address); } } else { setAndEmitErrorOccurred(QKnxNetIpServerDiscoveryAgent::Error::NotIPv4, @@ -354,6 +562,99 @@ void QKnxNetIpServerDiscoveryAgentPrivate::start() } } +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 diff --git a/src/knx/netip/qknxnetipserverdiscoveryagent_p.h b/src/knx/netip/qknxnetipserverdiscoveryagent_p.h index 960c214..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) @@ -73,6 +153,9 @@ public: 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: @@ -102,6 +185,9 @@ private: 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 d0203ad..6df5307 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. diff --git a/src/knx/netip/qknxnetipserverinfo.h b/src/knx/netip/qknxnetipserverinfo.h index da0a402..3d7ad48 100644 --- a/src/knx/netip/qknxnetipserverinfo.h +++ b/src/knx/netip/qknxnetipserverinfo.h @@ -47,6 +47,7 @@ struct QKnxNetIpServerInfoPrivate; class Q_KNX_EXPORT QKnxNetIpServerInfo final { + friend class Discoverer; friend class QKnxNetIpServerDiscoveryAgentPrivate; friend class QKnxNetIpServerDescriptionAgentPrivate; |