diff options
Diffstat (limited to 'src/knx/netip/qknxnetipserverdiscoveryagent.cpp')
-rw-r--r-- | src/knx/netip/qknxnetipserverdiscoveryagent.cpp | 389 |
1 files changed, 45 insertions, 344 deletions
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(); } /*! |