added upnp service
This commit is contained in:
parent
dbb52300aa
commit
e48c9e4497
2
debian/control
vendored
2
debian/control
vendored
@ -27,7 +27,7 @@ Architecture: any
|
|||||||
Depends: libqt5network5,
|
Depends: libqt5network5,
|
||||||
libqt5gui5,
|
libqt5gui5,
|
||||||
libqt5sql5,
|
libqt5sql5,
|
||||||
libqt5bluetooth5,
|
libqt5xml5,
|
||||||
libguh1 (= ${binary:Version}),
|
libguh1 (= ${binary:Version}),
|
||||||
${shlibs:Depends},
|
${shlibs:Depends},
|
||||||
${misc:Depends}
|
${misc:Depends}
|
||||||
|
|||||||
@ -188,7 +188,7 @@ void GuhSettings::remove(const QString &key)
|
|||||||
|
|
||||||
void GuhSettings::setValue(const QString &key, const QVariant &value)
|
void GuhSettings::setValue(const QString &key, const QVariant &value)
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(m_role != GuhSettings::SettingsRoleGlobal, "GuhSettings", "Bad settings usage. The global settings file should be read only.");
|
//Q_ASSERT_X(m_role != GuhSettings::SettingsRoleGlobal, "GuhSettings", "Bad settings usage. The global settings file should be read only.");
|
||||||
m_settings->setValue(key, value);
|
m_settings->setValue(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,11 @@
|
|||||||
|
|
||||||
#include "upnpdiscovery.h"
|
#include "upnpdiscovery.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
#include "guhsettings.h"
|
||||||
|
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
|
||||||
/*! Construct the hardware resource UpnpDiscovery with the given \a parent. */
|
/*! Construct the hardware resource UpnpDiscovery with the given \a parent. */
|
||||||
UpnpDiscovery::UpnpDiscovery(QObject *parent) :
|
UpnpDiscovery::UpnpDiscovery(QObject *parent) :
|
||||||
@ -75,9 +80,17 @@ UpnpDiscovery::UpnpDiscovery(QObject *parent) :
|
|||||||
m_networkAccessManager = new QNetworkAccessManager(this);
|
m_networkAccessManager = new QNetworkAccessManager(this);
|
||||||
connect(m_networkAccessManager, &QNetworkAccessManager::finished, this, &UpnpDiscovery::replyFinished);
|
connect(m_networkAccessManager, &QNetworkAccessManager::finished, this, &UpnpDiscovery::replyFinished);
|
||||||
|
|
||||||
connect(this,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(error(QAbstractSocket::SocketError)));
|
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
|
||||||
connect(this, &UpnpDiscovery::readyRead, this, &UpnpDiscovery::readData);
|
connect(this, &UpnpDiscovery::readyRead, this, &UpnpDiscovery::readData);
|
||||||
|
|
||||||
|
m_notificationTimer = new QTimer(this);
|
||||||
|
m_notificationTimer->setInterval(3000);
|
||||||
|
m_notificationTimer->setSingleShot(false);
|
||||||
|
|
||||||
|
connect(m_notificationTimer, &QTimer::timeout, this, &UpnpDiscovery::notificationTimeout);
|
||||||
|
|
||||||
|
m_notificationTimer->start();
|
||||||
|
|
||||||
qCDebug(dcDeviceManager) << "--> UPnP discovery created successfully.";
|
qCDebug(dcDeviceManager) << "--> UPnP discovery created successfully.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,9 +120,56 @@ void UpnpDiscovery::requestDeviceInformation(const QNetworkRequest &networkReque
|
|||||||
m_informationRequestList.insert(replay, upnpDeviceDescriptor);
|
m_informationRequestList.insert(replay, upnpDeviceDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpnpDiscovery::respondToSearchRequest()
|
||||||
|
{
|
||||||
|
GuhSettings settings(GuhSettings::SettingsRoleDevices);
|
||||||
|
settings.beginGroup("guhd");
|
||||||
|
QByteArray uuid = settings.value("uuid", QVariant()).toByteArray();
|
||||||
|
if (uuid.isEmpty()) {
|
||||||
|
uuid = QUuid::createUuid().toByteArray().replace("{", "").replace("}","");
|
||||||
|
settings.setValue("uuid", uuid);
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
GuhSettings globalSettings(GuhSettings::SettingsRoleGlobal);
|
||||||
|
globalSettings.beginGroup("WebServer");
|
||||||
|
int port = settings.value("port", 3333).toInt();
|
||||||
|
bool useSsl = settings.value("https", false).toBool();
|
||||||
|
globalSettings.endGroup();
|
||||||
|
|
||||||
|
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||||
|
// listen only on IPv4
|
||||||
|
foreach (QNetworkAddressEntry entry, interface.addressEntries()) {
|
||||||
|
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
|
QString locationString;
|
||||||
|
if (useSsl) {
|
||||||
|
locationString = "https://" + entry.ip().toString() + ":" + QString::number(port) + "/server.xml";
|
||||||
|
} else {
|
||||||
|
locationString = "http://" + entry.ip().toString() + ":" + QString::number(port) + "/server.xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
||||||
|
QByteArray rootdeviceResponseMessage = QByteArray("HTTP/1.1 200 OK\r\n"
|
||||||
|
"CACHE-CONTROL: max-age=1900\r\n"
|
||||||
|
"DATE: " + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT\r\n"
|
||||||
|
"EXT:\r\n"
|
||||||
|
"CONTENT-LENGTH:0\r\n"
|
||||||
|
"LOCATION: " + locationString.toUtf8() + "\r\n"
|
||||||
|
"SERVER: guh/" + QByteArray(GUH_VERSION_STRING) + " UPnP/1.1 \r\n"
|
||||||
|
"ST:upnp:rootdevice\r\n"
|
||||||
|
"USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n"
|
||||||
|
"\r\n");
|
||||||
|
|
||||||
|
sendToMulticast(rootdeviceResponseMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*! This method will be called to send the SSDP message \a data to the UPnP multicast.*/
|
/*! This method will be called to send the SSDP message \a data to the UPnP multicast.*/
|
||||||
void UpnpDiscovery::sendToMulticast(const QByteArray &data)
|
void UpnpDiscovery::sendToMulticast(const QByteArray &data)
|
||||||
{
|
{
|
||||||
|
qCDebug(dcHardware) << "sending to multicast\n" << data;
|
||||||
writeDatagram(data, m_host, m_port);
|
writeDatagram(data, m_host, m_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +190,13 @@ void UpnpDiscovery::readData()
|
|||||||
readDatagram(data.data(), data.size(), &hostAddress);
|
readDatagram(data.data(), data.size(), &hostAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.contains("M-SEARCH")) {
|
||||||
|
qCDebug(dcHardware) << "--------------------------------------";
|
||||||
|
qCDebug(dcHardware) << "UPnP data:" << hostAddress.toString() << "\n" << data;
|
||||||
|
respondToSearchRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.contains("NOTIFY")) {
|
if (data.contains("NOTIFY")) {
|
||||||
emit upnpNotify(data);
|
emit upnpNotify(data);
|
||||||
return;
|
return;
|
||||||
@ -236,6 +303,55 @@ void UpnpDiscovery::replyFinished(QNetworkReply *reply)
|
|||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpnpDiscovery::notificationTimeout()
|
||||||
|
{
|
||||||
|
GuhSettings settings(GuhSettings::SettingsRoleDevices);
|
||||||
|
settings.beginGroup("guhd");
|
||||||
|
QByteArray uuid = settings.value("uuid", QVariant()).toByteArray();
|
||||||
|
if (uuid.isEmpty()) {
|
||||||
|
uuid = QUuid::createUuid().toByteArray().replace("{", "").replace("}","");
|
||||||
|
settings.setValue("uuid", uuid);
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
GuhSettings globalSettings(GuhSettings::SettingsRoleGlobal);
|
||||||
|
globalSettings.beginGroup("WebServer");
|
||||||
|
int port = settings.value("port", 3333).toInt();
|
||||||
|
bool useSsl = settings.value("https", false).toBool();
|
||||||
|
globalSettings.endGroup();
|
||||||
|
|
||||||
|
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||||
|
// listen only on IPv4
|
||||||
|
foreach (QNetworkAddressEntry entry, interface.addressEntries()) {
|
||||||
|
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
|
QString locationString;
|
||||||
|
if (useSsl) {
|
||||||
|
locationString = "https://" + entry.ip().toString() + ":" + QString::number(port) + "/server.xml";
|
||||||
|
} else {
|
||||||
|
locationString = "http://" + entry.ip().toString() + ":" + QString::number(port) + "/server.xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
||||||
|
QByteArray rootdeviceResponseMessage = QByteArray("NOTIFY * HTTP/1.1\r\n"
|
||||||
|
"CACHE-CONTROL: max-age=1900\r\n"
|
||||||
|
"HOST:239.255.255.250:1900\r\n"
|
||||||
|
"NT:urn:schemas-upnp-org:device:Basic:1\r\n"
|
||||||
|
"NTS:ssdp:alive\r\n"
|
||||||
|
"DATE: " + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT\r\n"
|
||||||
|
"EXT:\r\n"
|
||||||
|
"CONTENT-LENGTH:0\r\n"
|
||||||
|
"LOCATION: " + locationString.toUtf8() + "\r\n"
|
||||||
|
"SERVER: guh/" + QByteArray(GUH_VERSION_STRING) + " UPnP/1.1 \r\n"
|
||||||
|
"USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n"
|
||||||
|
"\r\n");
|
||||||
|
|
||||||
|
sendToMulticast(rootdeviceResponseMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void UpnpDiscovery::discoverTimeout()
|
void UpnpDiscovery::discoverTimeout()
|
||||||
{
|
{
|
||||||
UpnpDiscoveryRequest *discoveryRequest = static_cast<UpnpDiscoveryRequest*>(sender());
|
UpnpDiscoveryRequest *discoveryRequest = static_cast<UpnpDiscoveryRequest*>(sender());
|
||||||
|
|||||||
@ -24,19 +24,17 @@
|
|||||||
#include <QUdpSocket>
|
#include <QUdpSocket>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTimer>
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QXmlStreamReader>
|
|
||||||
#include <QXmlStreamWriter>
|
|
||||||
|
|
||||||
#include "upnpdiscoveryrequest.h"
|
#include "upnpdiscoveryrequest.h"
|
||||||
#include "upnpdevicedescriptor.h"
|
#include "upnpdevicedescriptor.h"
|
||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
|
|
||||||
// reference: http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
|
// Discovering UPnP devices reference: http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
|
||||||
|
// guh basic device reference: http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf
|
||||||
|
|
||||||
class UpnpDiscoveryRequest;
|
class UpnpDiscoveryRequest;
|
||||||
|
|
||||||
@ -52,12 +50,15 @@ private:
|
|||||||
QHostAddress m_host;
|
QHostAddress m_host;
|
||||||
qint16 m_port;
|
qint16 m_port;
|
||||||
|
|
||||||
|
QTimer *m_notificationTimer;
|
||||||
|
|
||||||
QNetworkAccessManager *m_networkAccessManager;
|
QNetworkAccessManager *m_networkAccessManager;
|
||||||
|
|
||||||
QList<UpnpDiscoveryRequest *> m_discoverRequests;
|
QList<UpnpDiscoveryRequest *> m_discoverRequests;
|
||||||
QHash<QNetworkReply*,UpnpDeviceDescriptor> m_informationRequestList;
|
QHash<QNetworkReply*,UpnpDeviceDescriptor> m_informationRequestList;
|
||||||
|
|
||||||
void requestDeviceInformation(const QNetworkRequest &networkRequest, const UpnpDeviceDescriptor &upnpDeviceDescriptor);
|
void requestDeviceInformation(const QNetworkRequest &networkRequest, const UpnpDeviceDescriptor &upnpDeviceDescriptor);
|
||||||
|
void respondToSearchRequest();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -69,6 +70,7 @@ private slots:
|
|||||||
void error(QAbstractSocket::SocketError error);
|
void error(QAbstractSocket::SocketError error);
|
||||||
void readData();
|
void readData();
|
||||||
void replyFinished(QNetworkReply *reply);
|
void replyFinished(QNetworkReply *reply);
|
||||||
|
void notificationTimeout();
|
||||||
void discoverTimeout();
|
void discoverTimeout();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,7 @@ SOURCES += $$top_srcdir/server/guhcore.cpp \
|
|||||||
$$top_srcdir/server/rest/pluginsresource.cpp \
|
$$top_srcdir/server/rest/pluginsresource.cpp \
|
||||||
$$top_srcdir/server/rest/rulesresource.cpp \
|
$$top_srcdir/server/rest/rulesresource.cpp \
|
||||||
|
|
||||||
|
|
||||||
HEADERS += $$top_srcdir/server/guhcore.h \
|
HEADERS += $$top_srcdir/server/guhcore.h \
|
||||||
$$top_srcdir/server/tcpserver.h \
|
$$top_srcdir/server/tcpserver.h \
|
||||||
$$top_srcdir/server/ruleengine.h \
|
$$top_srcdir/server/ruleengine.h \
|
||||||
|
|||||||
@ -8,7 +8,7 @@ INCLUDEPATH += ../libguh jsonrpc
|
|||||||
target.path = /usr/bin
|
target.path = /usr/bin
|
||||||
INSTALLS += target
|
INSTALLS += target
|
||||||
|
|
||||||
QT += sql
|
QT += sql xml
|
||||||
|
|
||||||
LIBS += -L$$top_builddir/libguh/ -lguh
|
LIBS += -L$$top_builddir/libguh/ -lguh
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ include(server.pri)
|
|||||||
include(qtservice/qtservice.pri)
|
include(qtservice/qtservice.pri)
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
guhservice.cpp \
|
guhservice.cpp
|
||||||
|
|
||||||
boblight {
|
boblight {
|
||||||
xcompile {
|
xcompile {
|
||||||
@ -28,4 +28,4 @@ boblight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
guhservice.h \
|
guhservice.h
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
|
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
|
||||||
@ -79,6 +78,8 @@
|
|||||||
#include "rest/restresource.h"
|
#include "rest/restresource.h"
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QSslSocket>
|
#include <QSslSocket>
|
||||||
@ -118,6 +119,7 @@ WebServer::WebServer(const QSslConfiguration &sslConfiguration, QObject *parent)
|
|||||||
// check SSL
|
// check SSL
|
||||||
if (m_useSsl && m_sslConfiguration.isNull())
|
if (m_useSsl && m_sslConfiguration.isNull())
|
||||||
m_useSsl = false;
|
m_useSsl = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Destructor of this \l{WebServer}. */
|
/*! Destructor of this \l{WebServer}. */
|
||||||
@ -146,6 +148,25 @@ void WebServer::sendHttpReply(HttpReply *reply)
|
|||||||
socket->write(reply->data());
|
socket->write(reply->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WebServer::port() const
|
||||||
|
{
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QHostAddress> WebServer::serverAddressList()
|
||||||
|
{
|
||||||
|
QList<QHostAddress> addresses;
|
||||||
|
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||||
|
// listen only on IPv4
|
||||||
|
foreach (QNetworkAddressEntry entry, interface.addressEntries()) {
|
||||||
|
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
|
addresses.append(entry.ip());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName)
|
bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName)
|
||||||
{
|
{
|
||||||
QFileInfo file(fileName);
|
QFileInfo file(fileName);
|
||||||
@ -195,6 +216,135 @@ QString WebServer::fileName(const QString &query)
|
|||||||
return m_webinterfaceDir.path() + fileName;
|
return m_webinterfaceDir.path() + fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray WebServer::createServerXmlDocument(QHostAddress address)
|
||||||
|
{
|
||||||
|
GuhSettings settings(GuhSettings::SettingsRoleDevices);
|
||||||
|
settings.beginGroup("guhd");
|
||||||
|
QByteArray uuid = settings.value("uuid", QVariant()).toByteArray();
|
||||||
|
if (uuid.isEmpty()) {
|
||||||
|
uuid = QUuid::createUuid().toByteArray().replace("{", "").replace("}","");
|
||||||
|
settings.setValue("uuid", uuid);
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
|
QXmlStreamWriter writer(&data);
|
||||||
|
writer.setAutoFormatting(true);
|
||||||
|
writer.writeStartDocument("1.0");
|
||||||
|
writer.writeStartElement("root");
|
||||||
|
writer.writeAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
|
||||||
|
|
||||||
|
writer.writeStartElement("specVersion");
|
||||||
|
writer.writeTextElement("major", "1");
|
||||||
|
writer.writeTextElement("minor", "1");
|
||||||
|
writer.writeEndElement(); // specVersion
|
||||||
|
|
||||||
|
// if (m_useSsl) {
|
||||||
|
// writer.writeTextElement("URLBase", "https://" + address.toString() + ":" + QString::number(m_port));
|
||||||
|
// } else {
|
||||||
|
// writer.writeTextElement("URLBase", "http://" + address.toString() + ":" + QString::number(m_port));
|
||||||
|
// }
|
||||||
|
writer.writeStartElement("device");
|
||||||
|
writer.writeTextElement("deviceType", "urn:schemas-upnp-org:device:Basic:1");
|
||||||
|
writer.writeTextElement("friendlyName", "guhd");
|
||||||
|
writer.writeTextElement("manufacturer", "ARGE guh");
|
||||||
|
writer.writeTextElement("manufacturerURL", "http://guh.guru");
|
||||||
|
writer.writeTextElement("modelDescription", "Home automation server");
|
||||||
|
writer.writeTextElement("modelName", "guhd");
|
||||||
|
writer.writeTextElement("modelNumber", GUH_VERSION_STRING);
|
||||||
|
writer.writeTextElement("modelURL", "http://guh.io"); // (optional)
|
||||||
|
writer.writeTextElement("UDN", "uuid:" + uuid);
|
||||||
|
if (m_useSsl) {
|
||||||
|
writer.writeTextElement("presentationURL", "https://" + address.toString() + ":" + QString::number(m_port));
|
||||||
|
} else {
|
||||||
|
writer.writeTextElement("presentationURL", "http://" + address.toString() + ":" + QString::number(m_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
//writer.writeTextElement("presentationURL", "/");
|
||||||
|
|
||||||
|
writer.writeStartElement("iconList");
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "8");
|
||||||
|
writer.writeTextElement("height", "8");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-8x8.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "16");
|
||||||
|
writer.writeTextElement("height", "16");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-16x16.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "22");
|
||||||
|
writer.writeTextElement("height", "22");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-22x22.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "32");
|
||||||
|
writer.writeTextElement("height", "32");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-32x32.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "48");
|
||||||
|
writer.writeTextElement("height", "48");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-48x48.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "64");
|
||||||
|
writer.writeTextElement("height", "64");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-64x64.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "128");
|
||||||
|
writer.writeTextElement("height", "128");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-128x128.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "256");
|
||||||
|
writer.writeTextElement("height", "256");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-256x256.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeStartElement("icon");
|
||||||
|
writer.writeTextElement("mimetype", "image/png");
|
||||||
|
writer.writeTextElement("width", "512");
|
||||||
|
writer.writeTextElement("height", "512");
|
||||||
|
writer.writeTextElement("depth", "24");
|
||||||
|
writer.writeTextElement("url", "/icons/guh-logo-512x512.png");
|
||||||
|
writer.writeEndElement(); // icon
|
||||||
|
|
||||||
|
writer.writeEndElement(); // iconList
|
||||||
|
|
||||||
|
writer.writeEndElement(); // device
|
||||||
|
writer.writeEndElement(); // root
|
||||||
|
writer.writeEndDocument();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
HttpReply *WebServer::processIconRequest(const QString &fileName)
|
HttpReply *WebServer::processIconRequest(const QString &fileName)
|
||||||
{
|
{
|
||||||
if (!fileName.endsWith(".png"))
|
if (!fileName.endsWith(".png"))
|
||||||
@ -217,6 +367,17 @@ HttpReply *WebServer::processIconRequest(const QString &fileName)
|
|||||||
return RestResource::createErrorReply(HttpReply::NotFound);
|
return RestResource::createErrorReply(HttpReply::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QHostAddress WebServer::getServerAddress(QHostAddress clientAddress)
|
||||||
|
{
|
||||||
|
foreach (QHostAddress address, serverAddressList()) {
|
||||||
|
if (clientAddress.isInSubnet(QHostAddress::parseSubnet(address.toString() + "/24"))) {
|
||||||
|
qCDebug(dcWebServer) << "server for" << clientAddress.toString() << " ->" << address.toString();
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
void WebServer::incomingConnection(qintptr socketDescriptor)
|
void WebServer::incomingConnection(qintptr socketDescriptor)
|
||||||
{
|
{
|
||||||
if (!m_enabled)
|
if (!m_enabled)
|
||||||
@ -363,6 +524,20 @@ void WebServer::readClient()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check server.xml call
|
||||||
|
if (request.url().path() == "/server.xml" && request.method() == HttpRequest::Get) {
|
||||||
|
qCDebug(dcWebServer) << "server XML request call";
|
||||||
|
HttpReply *reply = RestResource::createSuccessReply();
|
||||||
|
reply->setHeader(HttpReply::ContentTypeHeader, "text/xml");
|
||||||
|
QHostAddress serverAddress = getServerAddress(socket->peerAddress());
|
||||||
|
reply->setPayload(createServerXmlDocument(serverAddress));
|
||||||
|
reply->setClientId(clientId);
|
||||||
|
sendHttpReply(reply);
|
||||||
|
reply->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// request for a file...
|
// request for a file...
|
||||||
if (request.method() == HttpRequest::Get) {
|
if (request.method() == HttpRequest::Get) {
|
||||||
// check if the webinterface dir does exist, otherwise a filerequest is not relevant
|
// check if the webinterface dir does exist, otherwise a filerequest is not relevant
|
||||||
@ -474,17 +649,20 @@ void WebServer::onError(QAbstractSocket::SocketError error)
|
|||||||
/*! Returns true if this \l{WebServer} started successfully. */
|
/*! Returns true if this \l{WebServer} started successfully. */
|
||||||
bool WebServer::startServer()
|
bool WebServer::startServer()
|
||||||
{
|
{
|
||||||
if (!listen(QHostAddress::Any, m_port)) {
|
if (!listen(QHostAddress::AnyIPv4, m_port)) {
|
||||||
qCWarning(dcConnection) << "Webserver could not listen on" << serverAddress().toString() << m_port;
|
qCWarning(dcConnection) << "Webserver could not listen on" << serverAddress().toString() << m_port;
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_useSsl) {
|
foreach (QHostAddress address, serverAddressList()) {
|
||||||
qCDebug(dcConnection) << "Started webserver on" << QString("https://%1:%2").arg(serverAddress().toString()).arg(m_port);
|
if (m_useSsl) {
|
||||||
} else {
|
qCDebug(dcConnection) << "Started webserver on" << QString("https://%1:%2").arg(address.toString()).arg(m_port);
|
||||||
qCDebug(dcConnection) << "Started webserver on" << QString("http://%1:%2").arg(serverAddress().toString()).arg(m_port);
|
} else {
|
||||||
|
qCDebug(dcConnection) << "Started webserver on" << QString("http://%1:%2").arg(address.toString()).arg(m_port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,6 +75,9 @@ public:
|
|||||||
~WebServer();
|
~WebServer();
|
||||||
|
|
||||||
void sendHttpReply(HttpReply *reply);
|
void sendHttpReply(HttpReply *reply);
|
||||||
|
int port() const;
|
||||||
|
QList<QHostAddress> serverAddressList();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, QSslSocket *> m_clientList;
|
QHash<QUuid, QSslSocket *> m_clientList;
|
||||||
@ -91,7 +94,9 @@ private:
|
|||||||
bool verifyFile(QSslSocket *socket, const QString &fileName);
|
bool verifyFile(QSslSocket *socket, const QString &fileName);
|
||||||
QString fileName(const QString &query);
|
QString fileName(const QString &query);
|
||||||
|
|
||||||
|
QByteArray createServerXmlDocument(QHostAddress address);
|
||||||
HttpReply *processIconRequest(const QString &fileName);
|
HttpReply *processIconRequest(const QString &fileName);
|
||||||
|
QHostAddress getServerAddress(QHostAddress clientAddress);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void incomingConnection(qintptr socketDescriptor) override;
|
void incomingConnection(qintptr socketDescriptor) override;
|
||||||
|
|||||||
Reference in New Issue
Block a user