mDNS Support (#1452)

* Allow build, if no grabbers are enabled

* Align available functions to right Qt version

* Update to next development version

* Align available functions to right Qt version

* fix workflows (apt/nightly)

* Disable QNetworkConfigurationManager deprecation warnings

* Initial go on Smart Pointers

* Add Deallocation

* Correct QT_WARNING_DISABLE_DEPRECATED (available since 5.9)

* Cluster Build Variables

* Hyperion Light

* Address build warnings

* Hyperion Light - UI

* Update Protobuf to latest master

* Removed compiler warnings

* Added restart ability to systray

* Correct Protobuf

* Ignore 'no-return' warning on protobuf build

* hyperion-remote: Fix auto discovery of hyperion server

* Fix Qt version override

* Update changelog

* Remove Grabber Components, if no Grabber exists

* Standalone Grabber - Fix fps default

* Remote Control - Have Source Selction accrosswhole screen

* Enable Blackborder detection only, if relevant input sources available

* Enable Blackborder detection only, if relevant input sources available

* Remote UI - rearrange containers

* Checkout

* Fix compilation on windows

* Re-added qmdnsengine template cmake

* chrono added for linux

* Removed existing AVAHI/Bonjour, allow to enable/disable mDNS

* hyperiond macos typo fix

* Fix macOS Bundle build

* Fix macOS bundle info details

* Correct CMake files

* Removed existing AVAHI/Bonjour (2)

* Share hyperion's services via mDNS

* Add mDNS Browser and mDNS for LED-Devices

* Support mDNS discovery for standalone grabbers

* Remove ZLib Dependency & Cleanup

* mDNS - hanle 2.local2 an ".local." domains equally

* Hue - Link discovery to bridge class, workaround port 443 for mDNS discovery

* Fix save button state when switching between devices

* Removed sessions (of other hyperions)

* mDNS Publisher - Simplify service naming

* mDNS refactoring & Forwarder discovery

* mDNS Updates to use device service name

* Consistency of standalone grabbers with mDNS Service Registry

* Merge branch 'hyperion-project:master' into mDNS

* Start JSON and WebServers only after Instance 0 is available

* Remove bespoke qDebug Output again

* MDNS updates and refactor Forwarder

* Minor updates

* Upgrade to CMake 3.1

* typo

* macOS fix

* Correct merge

* - Remove dynamic linker flag from standalone dispmanX Grabber
- Added ability to use system qmdns libs

* Cec handler library will load at runtime

* typo fix

* protobuf changes

* mDNS changes for Windows/macOS

* test window build qmdnsengine

* absolute path to protobuf cmake dir

* Rework Hue Wizard supporting mDNS

* LED-Devices - Retry support + Refactoring (excl. Hue)

* LED-Devices - Refactoring/Retry support Hue + additional alignments

* Address LGTM findings

* Fix CI-Build, revert test changes

* Build Windows in Release mode to avoid python problem

* Correct that WebServerObject is available earlier

* Ensure that instance name in logs for one instance are presented

* Update content LEDs

* Rework mDNS Address lookup

* Fix LED UI

* Fix for non mDNS Services (ignore default port)

* Disbale device when now input is available

* Revert back some updates, ensure last color is updated when switched on

* Handle reopening case and changed IP, port for API-calls

* Add UPD-DDP Device

* WLED support for DDP

* Fix printout

* LEDDevice - Allow more retries, udapte defaults

* LED-Net Devices - Select Custom device, if configured

Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
Co-authored-by: Paulchen Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
LordGrey
2022-05-01 19:42:47 +02:00
committed by GitHub
parent 3ef4ebc1a4
commit e9936e131b
148 changed files with 5885 additions and 4459 deletions

View File

@@ -31,6 +31,30 @@ struct ColorRgb
static const ColorRgb YELLOW;
/// 'White' RgbColor (255, 255, 255)
static const ColorRgb WHITE;
ColorRgb() = default;
ColorRgb(uint8_t _red, uint8_t _green,uint8_t _blue):
red(_red),
green(_green),
blue(_blue)
{
}
ColorRgb operator-(const ColorRgb& b) const
{
ColorRgb a(*this);
a.red -= b.red;
a.green -= b.green;
a.blue -= b.blue;
return a;
}
QString toQString() const
{
return QString("(%1,%2,%3)").arg(red).arg(green).arg(blue);
}
};
/// Assert to ensure that the size of the structure is 'only' 3 bytes

View File

@@ -1,12 +1,17 @@
#pragma once
#include <utils/Logger.h>
#include <QTcpServer>
#include <QUrl>
#include <QHostAddress>
#include <QHostInfo>
#include <HyperionConfig.h>
#include <utils/Logger.h>
#ifdef ENABLE_MDNS
#include <mdns/MdnsBrowser.h>
#endif
namespace NetUtils {
const int MAX_PORT = 65535;
@@ -38,15 +43,15 @@ namespace NetUtils {
///
/// @brief Check if the port is in the valid range
/// @param log The logger of the caller to print///
/// @param[in] port The port to be tested
/// @param[in] port The port to be tested (port = -1 is ignored for testing)
/// @param[in] host A hostname/IP-address to make reference to during logging
/// @return True on success else false
///
inline bool isValidPort(Logger* log, int port, const QString& host)
{
if (port <= 0 || port > MAX_PORT)
if ((port <= 0 || port > MAX_PORT) && port != -1)
{
Error(log, "Invalid port [%d] for host: %s!", port, QSTRING_CSTR(host));
Error(log, "Invalid port [%d] for host: (%s)! - Port must be in range [0 - %d]", port, QSTRING_CSTR(host), MAX_PORT);
return false;
}
return true;
@@ -59,7 +64,7 @@ namespace NetUtils {
/// @param[in/out] port The resolved port, if available.
/// @return True on success else false
///
inline bool resolveHostPort(const QString& address, QString& host, quint16& port)
inline bool resolveHostPort(const QString& address, QString& host, int& port)
{
if (address.isEmpty())
{
@@ -91,38 +96,109 @@ namespace NetUtils {
}
///
/// @brief Check if the port is in the valid range
/// @param log The logger of the caller to print
/// @param[in] address The port to be tested
/// @param[out] hostAddress A hostname to make reference to during logging
/// @return True on success else false
/// @brief Resolve a hostname (DNS/mDNS) into an IP-address. A given IP address will be passed through
/// @param[in/out] log The logger of the caller to print
/// @param[in] hostname The hostname to be resolved
/// @param[out] hostAddress The resolved IP-Address
/// @return True on success else false
///
inline bool resolveHostAddress(Logger* log, const QString& address, QHostAddress& hostAddress)
inline bool resolveMdDnsHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress)
{
bool isHostAddressOK{ false };
if (hostAddress.setAddress(address))
if (!hostname.isEmpty())
{
Debug(log, "Successfully parsed %s as an IP-address.", QSTRING_CSTR(hostAddress.toString()));
isHostAddressOK = true;
}
else
{
QHostInfo hostInfo = QHostInfo::fromName(address);
if (hostInfo.error() == QHostInfo::NoError)
#ifdef ENABLE_MDNS
if (hostname.endsWith(".local") || hostname.endsWith(".local."))
{
hostAddress = hostInfo.addresses().first();
Debug(log, "Successfully resolved IP-address (%s) for hostname (%s).", QSTRING_CSTR(hostAddress.toString()), QSTRING_CSTR(address));
isHostAddressOK = true;
QHostAddress resolvedAddress;
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "resolveAddress",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, isHostAddressOK),
Q_ARG(Logger*, log), Q_ARG(QString, hostname), Q_ARG(QHostAddress&, resolvedAddress));
hostAddress = resolvedAddress;
}
else
#endif
{
QString errortext = QString("Failed resolving IP-address for [%1], (%2) %3").arg(address).arg(hostInfo.error()).arg(hostInfo.errorString());
Error(log, "%s", QSTRING_CSTR(errortext));
isHostAddressOK = false;
if (hostAddress.setAddress(hostname))
{
//Debug(log, "IP-address (%s) not required to be resolved.", QSTRING_CSTR(hostAddress.toString()));
isHostAddressOK = true;
}
else
{
QHostInfo hostInfo = QHostInfo::fromName(hostname);
if (hostInfo.error() == QHostInfo::NoError)
{
hostAddress = hostInfo.addresses().at(0);
Debug(log, "Successfully resolved hostname (%s) to IP-address (%s)", QSTRING_CSTR(hostname), QSTRING_CSTR(hostAddress.toString()));
isHostAddressOK = true;
}
else
{
QString errortext = QString("Failed resolving hostname (%1) to IP-address. Error: (%2) %3").arg(hostname).arg(hostInfo.error()).arg(hostInfo.errorString());
Error(log, "%s", QSTRING_CSTR(errortext));
isHostAddressOK = false;
}
}
}
}
return isHostAddressOK;
}
}
///
/// @brief Resolve a hostname(DNS) or mDNS service name into an IP-address. A given IP address will be passed through
/// @param[in/out] log The logger of the caller to print
/// @param[in] hostname The hostname/mDNS service name to be resolved
/// @param[out] hostAddress The resolved IP-Address
/// @param[in/out] port The port provided by the mDNS service, if not mDNS the input port is returned
/// @return True on success else false
///
inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress, int& port)
{
bool areHostAddressPartOK{ false };
QString target {hostname};
#ifdef ENABLE_MDNS
if (hostname.endsWith("._tcp.local"))
{
//Treat hostname as service instance name that requires to be resolved into an mDNS-Hostname first
QMdnsEngine::Record service = MdnsBrowser::getInstance().getServiceInstanceRecord(hostname.toUtf8());
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, "Cannot resolve mDNS hostname for given service [%s]!", QSTRING_CSTR(hostname));
return areHostAddressPartOK;
}
}
#endif
QHostAddress resolvedAddress;
if (NetUtils::resolveMdDnsHostToAddress(log, target, resolvedAddress))
{
hostAddress = resolvedAddress;
if (hostname != hostAddress.toString())
{
Info(log, "Resolved hostname (%s) to IP-address (%s)", QSTRING_CSTR(hostname), QSTRING_CSTR(hostAddress.toString()));
}
if (NetUtils::isValidPort(log, port, hostAddress.toString()))
{
areHostAddressPartOK = true;
}
}
return areHostAddressPartOK;
}
inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress)
{
int ignoredPort {MAX_PORT};
return resolveHostToAddress(log, hostname, hostAddress, ignoredPort);
}
}