hyperion.ng/libsrc/ssdp/SSDPHandler.cpp

267 lines
6.9 KiB
C++
Raw Normal View History

2018-12-30 22:07:53 +01:00
#include <ssdp/SSDPHandler.h>
#include <webserver/WebServer.h>
#include "SSDPDescription.h"
#include <hyperion/Hyperion.h>
#include <HyperionConfig.h>
#include <hyperion/AuthManager.h>
2018-12-30 22:07:53 +01:00
#include <QNetworkInterface>
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
2018-12-30 22:07:53 +01:00
#include <QNetworkConfigurationManager>
#endif
2018-12-30 22:07:53 +01:00
2020-07-27 20:00:36 +02:00
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
#include <QRandomGenerator>
#endif
static const QString SSDP_IDENTIFIER("urn:hyperion-project.org:device:basic:1");
SSDPHandler::SSDPHandler(WebServer* webserver, quint16 flatBufPort, quint16 protoBufPort, quint16 jsonServerPort, quint16 sslPort, const QString& name, QObject* parent)
2018-12-30 22:07:53 +01:00
: SSDPServer(parent)
, _webserver(webserver)
, _localAddress()
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
2018-12-30 22:07:53 +01:00
, _NCA(nullptr)
#endif
2018-12-30 22:07:53 +01:00
{
setFlatBufPort(flatBufPort);
setProtoBufPort(protoBufPort);
setJsonServerPort(jsonServerPort);
setSSLServerPort(sslPort);
setHyperionName(name);
2018-12-30 22:07:53 +01:00
}
SSDPHandler::~SSDPHandler()
{
add Hue EntertainmentAPI + Forwarder & other Fixes (#592) * whitespaces + typo fixes * JS / LGTM fixes * SSDP Handler crash fix * MessageForwarder handlePriorityChanges Slave fixes * use aboutToQuit Signal * complete rewriten Hue Entertainment API structure combined Philips Hue and Entertainment API with new MbedTLS based SSL UDP Provider * add required cross-compile submodules * logical rebuild fn: initLeds, setLights + new logs -more detailed checks and error handling inside iniLeds and setLights - logical script procedure before ProviderUdpSSL init - first steps for multiple ProviderUdpSSL usage - better fallback support to old RestAPI, if entertainment api is not supported - just 4 u LordGrey: new log fn for cosmetic config outputs ;) * add OSX CompileHowTo - undo from CrossCompileHowTo * whitespace fixes * lightID toString fix * fix unsigned int E-API + debug output * bugfixes, reworked black signal detection, wizard: - change device config field light-ids from int to string -> real unsigned int fix - add signal detection brightness minimum threshold value 0.0 for 0% brightness - 1.0 for 100% brightness to count for blacklight signal detection reason: input may not 100% black, like mine - i have a deep dark gray input signal -> my threshold value is set to 0.005 for 0.5% minimum brightness = 1 (from max 255) to count as black - wizard optimations, with fallback without entertainment support (beta state) - whitespace fixes * cleanup + minor fixes * change fixed Hue UPD SSL config to _devConfig paras * Hotfix SSL Connection, new light models, wizard: - Fix UPD SSL Connection failed Problems - add new supported gamut C light models: LCG002, LCA001, LCA002, LCA003 - wizard: extend fallback support to classic mode + hints * whitespace, typo fix * uncheck useEntertainmentAPI, if noAPISupport detected + hint * coredump fix -> add _blackLightsTimer nullptr init * code cleanup / remove old debugs + whitespacefixes * add gamut C LCP001, LCP002 * SSL UDP config made more flexible + remove qDebug -> switch to hyerion.ng _log -> replace logCommand with verbose -> code cleanups etc... * extended mbedtls debugging infos * add adjustable ssl timeout settings * error handling * streamdebugger bugfixes * UPDSSL psk / psk_identity bugfixes! + hue wizard fn typo fix + - verbose option available without dependencies - whitespace fixes * Philips Hue Assistant now recognizes non-original bridges better... + Added note if no clientkey is set when using the entertainment API + User creation (+ clientkey) for non-original bridges can now also be used + Minor changes and bug fixes * CMAKE mbedTLS detection * minor bug fixes + code cleanups * FindMbedTLS.cmake remove Path-Hints + wizard.js: ajax timeout handling Test - content_grabber.js: run relevant code only, if V4L2_AVAIL is true: conf_grabber don't displays other devices, if V4L2 is not available * compile mbedtls via cmake as static lib * remove libmbedtls-dev from compileHowto / scripts * Fix Windows build * Fix windows build (part 2) * removed unnecessary osx x11 include directory path * QTimer Shutdown bugfix * cmake win32 fix + minor bugfixes * cmake debug msg used mbedtls libs * Bugfix: noSignalDetection wasn't switchedOn again if no signal was previously detected * Some code fixes based on alerts from lgtm.com Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
2020-05-22 19:40:50 +02:00
stopServer();
}
2018-12-30 22:07:53 +01:00
void SSDPHandler::initServer()
{
_uuid = AuthManager::getInstance()->getID();
SSDPServer::setUuid(_uuid);
// announce targets
_deviceList.push_back("upnp:rootdevice");
_deviceList.push_back("uuid:" + _uuid);
_deviceList.push_back(SSDP_IDENTIFIER);
2018-12-30 22:07:53 +01:00
// prep server
SSDPServer::initServer();
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
#endif
2018-12-30 22:07:53 +01:00
_NCA = new QNetworkConfigurationManager(this);
connect(_NCA, &QNetworkConfigurationManager::configurationChanged, this, &SSDPHandler::handleNetworkConfigurationChanged);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QT_WARNING_POP
#endif
#endif
2018-12-30 22:07:53 +01:00
// listen for mSearchRequestes
connect(this, &SSDPServer::msearchRequestReceived, this, &SSDPHandler::handleMSearchRequest);
// get localAddress from interface
if (!getLocalAddress().isEmpty())
2018-12-30 22:07:53 +01:00
{
_localAddress = getLocalAddress();
}
// startup if localAddress is found
2020-07-22 16:43:24 +02:00
bool isInited = false;
QMetaObject::invokeMethod(_webserver, "isInited", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isInited));
if (!_localAddress.isEmpty() && isInited)
2018-12-30 22:07:53 +01:00
{
handleWebServerStateChange(true);
}
}
add Hue EntertainmentAPI + Forwarder & other Fixes (#592) * whitespaces + typo fixes * JS / LGTM fixes * SSDP Handler crash fix * MessageForwarder handlePriorityChanges Slave fixes * use aboutToQuit Signal * complete rewriten Hue Entertainment API structure combined Philips Hue and Entertainment API with new MbedTLS based SSL UDP Provider * add required cross-compile submodules * logical rebuild fn: initLeds, setLights + new logs -more detailed checks and error handling inside iniLeds and setLights - logical script procedure before ProviderUdpSSL init - first steps for multiple ProviderUdpSSL usage - better fallback support to old RestAPI, if entertainment api is not supported - just 4 u LordGrey: new log fn for cosmetic config outputs ;) * add OSX CompileHowTo - undo from CrossCompileHowTo * whitespace fixes * lightID toString fix * fix unsigned int E-API + debug output * bugfixes, reworked black signal detection, wizard: - change device config field light-ids from int to string -> real unsigned int fix - add signal detection brightness minimum threshold value 0.0 for 0% brightness - 1.0 for 100% brightness to count for blacklight signal detection reason: input may not 100% black, like mine - i have a deep dark gray input signal -> my threshold value is set to 0.005 for 0.5% minimum brightness = 1 (from max 255) to count as black - wizard optimations, with fallback without entertainment support (beta state) - whitespace fixes * cleanup + minor fixes * change fixed Hue UPD SSL config to _devConfig paras * Hotfix SSL Connection, new light models, wizard: - Fix UPD SSL Connection failed Problems - add new supported gamut C light models: LCG002, LCA001, LCA002, LCA003 - wizard: extend fallback support to classic mode + hints * whitespace, typo fix * uncheck useEntertainmentAPI, if noAPISupport detected + hint * coredump fix -> add _blackLightsTimer nullptr init * code cleanup / remove old debugs + whitespacefixes * add gamut C LCP001, LCP002 * SSL UDP config made more flexible + remove qDebug -> switch to hyerion.ng _log -> replace logCommand with verbose -> code cleanups etc... * extended mbedtls debugging infos * add adjustable ssl timeout settings * error handling * streamdebugger bugfixes * UPDSSL psk / psk_identity bugfixes! + hue wizard fn typo fix + - verbose option available without dependencies - whitespace fixes * Philips Hue Assistant now recognizes non-original bridges better... + Added note if no clientkey is set when using the entertainment API + User creation (+ clientkey) for non-original bridges can now also be used + Minor changes and bug fixes * CMAKE mbedTLS detection * minor bug fixes + code cleanups * FindMbedTLS.cmake remove Path-Hints + wizard.js: ajax timeout handling Test - content_grabber.js: run relevant code only, if V4L2_AVAIL is true: conf_grabber don't displays other devices, if V4L2 is not available * compile mbedtls via cmake as static lib * remove libmbedtls-dev from compileHowto / scripts * Fix Windows build * Fix windows build (part 2) * removed unnecessary osx x11 include directory path * QTimer Shutdown bugfix * cmake win32 fix + minor bugfixes * cmake debug msg used mbedtls libs * Bugfix: noSignalDetection wasn't switchedOn again if no signal was previously detected * Some code fixes based on alerts from lgtm.com Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
2020-05-22 19:40:50 +02:00
void SSDPHandler::stopServer()
{
sendAnnounceList(false);
SSDPServer::stop();
}
2020-08-08 13:09:15 +02:00
void SSDPHandler::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
2018-12-30 22:07:53 +01:00
{
const QJsonObject& obj = config.object();
if (type == settings::FLATBUFSERVER)
2018-12-30 22:07:53 +01:00
{
if (obj["port"].toInt() != SSDPServer::getFlatBufPort())
2018-12-30 22:07:53 +01:00
{
SSDPServer::setFlatBufPort(obj["port"].toInt());
}
}
if (type == settings::PROTOSERVER)
{
if (obj["port"].toInt() != SSDPServer::getProtoBufPort())
{
SSDPServer::setProtoBufPort(obj["port"].toInt());
}
}
if (type == settings::JSONSERVER)
{
if (obj["port"].toInt() != SSDPServer::getJsonServerPort())
{
SSDPServer::setJsonServerPort(obj["port"].toInt());
2018-12-30 22:07:53 +01:00
}
}
if (type == settings::WEBSERVER)
{
if (obj["sslPort"].toInt() != SSDPServer::getSSLServerPort())
{
SSDPServer::setSSLServerPort(obj["sslPort"].toInt());
}
}
if (type == settings::GENERAL)
{
if (obj["name"].toString() != SSDPServer::getHyperionName())
{
SSDPServer::setHyperionName(obj["name"].toString());
}
}
2018-12-30 22:07:53 +01:00
}
2020-08-08 13:09:15 +02:00
void SSDPHandler::handleWebServerStateChange(bool newState)
2018-12-30 22:07:53 +01:00
{
if (newState)
2018-12-30 22:07:53 +01:00
{
// refresh info
2020-07-22 16:43:24 +02:00
QMetaObject::invokeMethod(_webserver, "setSSDPDescription", Qt::BlockingQueuedConnection, Q_ARG(QString, buildDesc()));
2018-12-30 22:07:53 +01:00
setDescriptionAddress(getDescAddress());
if (start())
sendAnnounceList(true);
2018-12-30 22:07:53 +01:00
}
else
{
2020-07-22 16:43:24 +02:00
QMetaObject::invokeMethod(_webserver, "setSSDPDescription", Qt::BlockingQueuedConnection, Q_ARG(QString, ""));
sendAnnounceList(false);
2018-12-30 22:07:53 +01:00
stop();
}
}
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
#endif
void SSDPHandler::handleNetworkConfigurationChanged(const QNetworkConfiguration& config)
2018-12-30 22:07:53 +01:00
{
// get localAddress from interface
QString localAddress = getLocalAddress();
if (!localAddress.isEmpty() && _localAddress != localAddress)
2018-12-30 22:07:53 +01:00
{
// revoke old ip
sendAnnounceList(false);
2018-12-30 22:07:53 +01:00
// update desc & notify new ip
_localAddress = localAddress;
2020-07-22 16:43:24 +02:00
QMetaObject::invokeMethod(_webserver, "setSSDPDescription", Qt::BlockingQueuedConnection, Q_ARG(QString, buildDesc()));
setDescriptionAddress(getDescAddress());
sendAnnounceList(true);
2018-12-30 22:07:53 +01:00
}
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QT_WARNING_POP
#endif
#endif
2018-12-30 22:07:53 +01:00
QString SSDPHandler::getLocalAddress() const
2018-12-30 22:07:53 +01:00
{
// get the first valid IPv4 address. This is probably not that one we actually want to announce
for (const auto& address : QNetworkInterface::allAddresses())
2018-12-30 22:07:53 +01:00
{
// is valid when, no loopback, IPv4
if (!address.isLoopback() && address.protocol() == QAbstractSocket::IPv4Protocol)
2018-12-30 22:07:53 +01:00
{
return address.toString();
}
}
return QString();
}
2020-08-08 13:09:15 +02:00
void SSDPHandler::handleMSearchRequest(const QString& target, const QString& mx, const QString address, quint16 port)
2018-12-30 22:07:53 +01:00
{
const auto respond = [=]() {
// when searched for all devices / root devices / basic device
if (target == "ssdp:all")
sendMSearchResponse(SSDP_IDENTIFIER, address, port);
else if (target == "upnp:rootdevice" || target == "urn:schemas-upnp-org:device:basic:1" || target == SSDP_IDENTIFIER)
sendMSearchResponse(target, address, port);
};
bool ok = false;
int maxDelay = mx.toInt(&ok);
if (ok)
{
/* Pick a random delay between 0 and MX seconds */
2020-07-27 20:00:36 +02:00
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
int randomDelay = QRandomGenerator::global()->generate() % (maxDelay * 1000);
#else
int randomDelay = qrand() % (maxDelay * 1000);
2020-07-27 20:00:36 +02:00
#endif
QTimer::singleShot(randomDelay, respond);
}
else
{
/* MX Header is not valid.
* Send response without delay */
respond();
}
2018-12-30 22:07:53 +01:00
}
QString SSDPHandler::getDescAddress() const
2018-12-30 22:07:53 +01:00
{
return getBaseAddress() + "description.xml";
2018-12-30 22:07:53 +01:00
}
QString SSDPHandler::getBaseAddress() const
2018-12-30 22:07:53 +01:00
{
2020-07-22 16:43:24 +02:00
quint16 port = 0;
QMetaObject::invokeMethod(_webserver, "getPort", Qt::BlockingQueuedConnection, Q_RETURN_ARG(quint16, port));
return QString("http://%1:%2/").arg(_localAddress).arg(port);
2018-12-30 22:07:53 +01:00
}
QString SSDPHandler::buildDesc() const
2018-12-30 22:07:53 +01:00
{
/// %1 base url http://192.168.0.177:8090/
/// %2 friendly name Hyperion (192.168.0.177)
2018-12-30 22:07:53 +01:00
/// %3 modelNumber 2.0.0
/// %4 serialNumber / UDN (H ID) Fjsa723dD0....
/// %5 json port 19444
/// %6 ssl server port 8092
/// %7 protobuf port 19445
/// %8 flatbuf port 19400
return SSDP_DESCRIPTION.arg(
getBaseAddress(),
QString("Hyperion (%1)").arg(_localAddress),
QString(HYPERION_VERSION),
_uuid,
QString::number(SSDPServer::getJsonServerPort()),
QString::number(SSDPServer::getSSLServerPort()),
QString::number(SSDPServer::getProtoBufPort()),
QString::number(SSDPServer::getFlatBufPort())
);
}
2020-08-08 13:09:15 +02:00
void SSDPHandler::sendAnnounceList(bool alive)
{
for (const auto& entry : _deviceList) {
alive ? SSDPServer::sendAlive(entry) : SSDPServer::sendByeBye(entry);
}
2018-12-30 22:07:53 +01:00
}
2020-07-22 16:43:24 +02:00