Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- LED-device updates queue up and let Hyperion crash (#1887)
- The color of the backlight threshold is green, not white/gray (#1899)
- Install - Ubuntu 25.10 unable to install due to libcec package (#1934)
- Fix concurrent mDNS resolution (#1906)

---

Expand All @@ -61,7 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Fixes:**
- WebUI unreachable via IPv6 (#1871)
- Align install_pr script working with default Qt6 builds & show authentication failures (#1871)

- **Build:**
- Added Debian Trixie to PR-builds for early testing

Expand Down
8 changes: 3 additions & 5 deletions include/mdns/MdnsBrowser.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <QByteArray>
#include <QMap>
#include <QJsonArray>
#include <QString>
#include <QSharedPointer>
#include <QScopedPointer>

Expand Down Expand Up @@ -88,10 +89,9 @@ public slots:
*/
void serviceRemoved(const QMdnsEngine::Service& service);

void isAddressResolved(QHostAddress address);
void isFirstAddressResolved(QHostAddress address);
void isFirstAddressResolved(QString hostname, QHostAddress address);

void isServiceRecordResolved(QMdnsEngine::Record serviceRecord) const;
void isServiceRecordResolved(QByteArray serviceInstance, QMdnsEngine::Record serviceRecord) const;

private slots:

Expand All @@ -101,8 +101,6 @@ private slots:
void onServiceUpdated(const QMdnsEngine::Service& service);
void onServiceRemoved(const QMdnsEngine::Service& service);

void onHostNameResolved(const QHostAddress& address);

private:
/// The logger instance for mDNS-Service
QSharedPointer<Logger> _log;
Expand Down
80 changes: 49 additions & 31 deletions include/utils/NetUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,15 @@ inline bool resolveMDnsHostToAddress(QSharedPointer<Logger> log, const QString&
QEventLoop loop;

// Connect the signal to capture the resolved address
QObject::connect(browser, &MdnsBrowser::isFirstAddressResolved, &loop, [&](QHostAddress addr) {
hostAddress = std::move(addr);
QString const requestedHostname = hostname;
QObject::connect(browser, &MdnsBrowser::isFirstAddressResolved, &loop,
[&, requestedHostname](const QString& resolvedHostname, const QHostAddress& addr) {
if (resolvedHostname.compare(requestedHostname, Qt::CaseInsensitive) != 0)
{
return;
}

hostAddress = addr;
loop.quit();
});

Expand Down Expand Up @@ -189,7 +196,14 @@ inline QMdnsEngine::Record resolveMDnsServiceRecord(const QByteArray& serviceIns
QEventLoop loop;

// Connect the signal to capture the resolved service record
QObject::connect(browser, &MdnsBrowser::isServiceRecordResolved, &loop, [&](QMdnsEngine::Record resolvedServiceRecord) {
QByteArray const requestedService = serviceInstance;
QObject::connect(browser, &MdnsBrowser::isServiceRecordResolved, &loop,
[&, requestedService](const QByteArray& emittedService, const QMdnsEngine::Record& resolvedServiceRecord) {
if (emittedService != requestedService)
{
return;
}

serviceRecord = resolvedServiceRecord;
loop.quit();
});
Expand Down Expand Up @@ -224,27 +238,29 @@ inline bool resolveHostToAddress(QSharedPointer<Logger> log, const QString& host
if (hostname.endsWith("._tcp.local"))
{
//Treat hostname as service instance name that requires to be resolved into an mDNS-Hostname first
QMdnsEngine::Record const service = resolveMDnsServiceRecord(hostname.toUtf8());
if (!service.target().isEmpty())
QByteArray requestedService = hostname.toUtf8();
if (!requestedService.endsWith('.'))
{
if (!service.target().isEmpty())
{
Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), service.target().constData(), service.port());
target = service.target();
port = service.port();
}
else
{
Error(log, "Failed to resolved service [%s] to an mDNS hostname", QSTRING_CSTR(hostname));
return false;
}
requestedService.append('.');
}
else

QMdnsEngine::Record const serviceRecord = resolveMDnsServiceRecord(hostname.toUtf8());
if (serviceRecord.name().isEmpty() || serviceRecord.target().isEmpty())
{
Error(log, "Cannot resolve mDNS hostname for given service [%s]!", QSTRING_CSTR(hostname));
return false;
}

if (serviceRecord.name() != requestedService)
{
Error(log, "Resolved record [%s] does not match requested service [%s]", serviceRecord.name().constData(), requestedService.constData());
return false;
}

Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), serviceRecord.target().constData(), serviceRecord.port());
target = serviceRecord.target();
port = serviceRecord.port();

QHostAddress resolvedAddress;
if (NetUtils::resolveMDnsHostToAddress(log, target, resolvedAddress))
{
Expand Down Expand Up @@ -286,27 +302,29 @@ inline bool resolveMdnsHost(QSharedPointer<Logger> log, QString& hostname, int&
if (hostname.endsWith("._tcp.local"))
{
//Treat hostname as service instance name that requires to be resolved into an mDNS-Hostname first
QMdnsEngine::Record const service = resolveMDnsServiceRecord(hostname.toUtf8());
if (!service.target().isEmpty())
QByteArray requestedService = hostname.toUtf8();
if (!requestedService.endsWith('.'))
{
if (!service.target().isEmpty())
{
Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), service.target().constData(), service.port());
target = service.target();
port = service.port();
}
else
{
Error(log, "Failed to resolved service [%s] to an mDNS hostname", QSTRING_CSTR(hostname));
return false;
}
requestedService.append('.');
}
else

QMdnsEngine::Record const serviceRecord = resolveMDnsServiceRecord(hostname.toUtf8());
if (serviceRecord.name().isEmpty() || serviceRecord.target().isEmpty())
{
Error(log, "Cannot resolve mDNS hostname for given service [%s]!", QSTRING_CSTR(hostname));
return false;
}

if (serviceRecord.name() != requestedService)
{
Error(log, "Resolved record [%s] does not match requested service [%s]", serviceRecord.name().constData(), requestedService.constData());
return false;
}

Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), serviceRecord.target().constData(), serviceRecord.port());
target = serviceRecord.target();
port = serviceRecord.port();

QHostAddress resolvedAddress;
if (NetUtils::resolveMDnsHostToAddress(log, target, resolvedAddress))
{
Expand Down
39 changes: 14 additions & 25 deletions libsrc/mdns/MdnsBrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,6 @@ void MdnsBrowser::onServiceRemoved(const QMdnsEngine::Service& service)
emit serviceRemoved(service);
}

void MdnsBrowser::onHostNameResolved(const QHostAddress& address)
{
DebugIf(verboseBrowser, _log, "for address [%s], Thread: %s", QSTRING_CSTR(address.toString()), QSTRING_CSTR(QThread::currentThread()->objectName()));

// Do not publish link local addresses
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
if (!address.isLinkLocal())
#else
if (!address.toString().startsWith("fe80"))
#endif
{
emit isAddressResolved(address);
}
}

void MdnsBrowser::resolveFirstAddress(QSharedPointer<Logger> log, const QString& hostname, std::chrono::milliseconds timeout)
{
qRegisterMetaType<QMdnsEngine::Message>("Message");
Expand All @@ -140,24 +125,28 @@ void MdnsBrowser::resolveFirstAddress(QSharedPointer<Logger> log, const QString&
if (hostname.endsWith(".local") || hostname.endsWith(".local."))
{
QMdnsEngine::Resolver const resolver (_server.get(), hostname.toUtf8(), _cache.get());
connect(&resolver, &QMdnsEngine::Resolver::resolved, this, &MdnsBrowser::onHostNameResolved);

DebugIf(verboseBrowser, log, "Wait for resolver on hostname [%s]", QSTRING_CSTR(hostname));

QEventLoop loop;
QTimer timer;

timer.setSingleShot(true);
connect(&timer, &QTimer::timeout, this, [&loop]() {
loop.quit(); // Stop waiting if timeout occurs
});
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);

connect(&resolver, &QMdnsEngine::Resolver::resolved, &loop, [ &loop, &resolvedAddress ](const QHostAddress& address) {
// Ignore link-local addresses
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
if (address.isLinkLocal())
#else
if (address.toString().startsWith("fe80"))
#endif
{
return;
}

std::unique_ptr<QObject> context{new QObject};
QObject* pcontext = context.get();
connect(this, &MdnsBrowser::isAddressResolved, pcontext, [ &loop, &resolvedAddress, context = std::move(context)](const QHostAddress &address) mutable {
resolvedAddress = address;
loop.quit();
context.reset();
});

timer.start(timeout);
Expand All @@ -177,7 +166,7 @@ void MdnsBrowser::resolveFirstAddress(QSharedPointer<Logger> log, const QString&
Error(log, "Hostname [%s] is not an mDNS hostname.", QSTRING_CSTR(hostname));
}

emit isFirstAddressResolved(resolvedAddress);
emit isFirstAddressResolved(hostname, resolvedAddress);
}

void MdnsBrowser::resolveServiceInstance(const QByteArray& serviceInstance, const std::chrono::milliseconds waitTime) const
Expand Down Expand Up @@ -225,7 +214,7 @@ void MdnsBrowser::resolveServiceInstance(const QByteArray& serviceInstance, cons
Debug(_log, "No service record found for service instance [%s]", service.constData());
}
}
emit isServiceRecordResolved(srvRecord);
emit isServiceRecordResolved(serviceInstance, srvRecord);
}

QMdnsEngine::Service MdnsBrowser::getFirstService(const QByteArray& serviceType, const QString& filter, const std::chrono::milliseconds waitTime) const
Expand Down
Loading