diff --git a/guh.pri b/guh.pri index ab494e17..0efd9240 100644 --- a/guh.pri +++ b/guh.pri @@ -2,7 +2,7 @@ GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"') # define protocol versions -JSON_PROTOCOL_VERSION=43 +JSON_PROTOCOL_VERSION=44 REST_API_VERSION=1 DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" \ diff --git a/libguh/coap/coappdublock.cpp b/libguh/coap/coappdublock.cpp index 5a7ba6e4..82d9d38c 100644 --- a/libguh/coap/coappdublock.cpp +++ b/libguh/coap/coappdublock.cpp @@ -18,6 +18,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include + #include "coappdublock.h" CoapPduBlock::CoapPduBlock() diff --git a/libguh/network/avahi/qtavahiservice.cpp b/libguh/network/avahi/qtavahiservice.cpp index d0549a1f..f9fe2fb4 100644 --- a/libguh/network/avahi/qtavahiservice.cpp +++ b/libguh/network/avahi/qtavahiservice.cpp @@ -86,8 +86,8 @@ QString QtAvahiService::serviceType() const return d_ptr->type; } -/*! Returns true if a new avahi service to the network with the given \a name, \a port and \a serviceType can be registered. */ -bool QtAvahiService::registerService(QString name, quint16 port, QString serviceType) +/*! Returns true if a new avahi service to the network with the given \a name, \a port \a serviceType and \a txt can be registered. */ +bool QtAvahiService::registerService(const QString &name, const quint16 &port, const QString &serviceType, const QHash &txt) { // check if the client is running if (!d_ptr->client->client || AVAHI_CLIENT_S_RUNNING != avahi_client_get_state(d_ptr->client->client)) @@ -104,16 +104,16 @@ bool QtAvahiService::registerService(QString name, quint16 port, QString service // if the group is empty if (avahi_entry_group_is_empty(d_ptr->group)) { // add the service - d_ptr->error = avahi_entry_group_add_service(d_ptr->group, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - (AvahiPublishFlags) 0, - d_ptr->name.toLatin1().data(), - d_ptr->type.toLatin1().data(), - 0, - 0, - (uint16_t)d_ptr->port, - NULL); + d_ptr->error = avahi_entry_group_add_service_strlst(d_ptr->group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + (AvahiPublishFlags) 0, + d_ptr->name.toLatin1().data(), + d_ptr->type.toLatin1().data(), + 0, + 0, + (uint16_t)d_ptr->port, + QtAvahiServicePrivate::createTxtList(txt)); // verify if the group has to be comitted if (!d_ptr->error) @@ -134,6 +134,9 @@ bool QtAvahiService::registerService(QString name, quint16 port, QString service */ void QtAvahiService::resetService() { + if (!d_ptr->group) + return; + avahi_entry_group_reset(d_ptr->group); } diff --git a/libguh/network/avahi/qtavahiservice.h b/libguh/network/avahi/qtavahiservice.h index 8ddae002..3773369b 100644 --- a/libguh/network/avahi/qtavahiservice.h +++ b/libguh/network/avahi/qtavahiservice.h @@ -21,6 +21,8 @@ #ifndef QTAVAHISERVICE_H #define QTAVAHISERVICE_H +#include +#include #include #include "libguh.h" @@ -48,7 +50,7 @@ public: QString name() const; QString serviceType() const; - bool registerService(QString name, quint16 port, QString serviceType = "_http._tcp"); + bool registerService(const QString &name, const quint16 &port, const QString &serviceType = "_http._tcp", const QHash &txt = QHash()); void resetService(); bool isValid() const; diff --git a/libguh/network/avahi/qtavahiservice_p.cpp b/libguh/network/avahi/qtavahiservice_p.cpp index 341228fc..8261d70f 100644 --- a/libguh/network/avahi/qtavahiservice_p.cpp +++ b/libguh/network/avahi/qtavahiservice_p.cpp @@ -20,6 +20,9 @@ #include "qtavahiservice_p.h" +#include +#include + QtAvahiServicePrivate::QtAvahiServicePrivate() : client(0), group(0), @@ -54,3 +57,18 @@ void QtAvahiServicePrivate::callback(AvahiEntryGroup *group, AvahiEntryGroupStat } } +AvahiStringList *QtAvahiServicePrivate::createTxtList(const QHash &txt) +{ + AvahiStringList *list = NULL; + if (txt.isEmpty()) + return list; + + const QStringList keys = txt.keys(); + list = avahi_string_list_new((keys.first() + '=' + txt[keys.first()]).toLatin1().constData(), nullptr); + for (const QString &key : keys.mid(1)) { + list = avahi_string_list_add_pair(list, key.toLatin1().constData(), txt[key].toLatin1().constData()); + } + + return list; +} + diff --git a/libguh/network/avahi/qtavahiservice_p.h b/libguh/network/avahi/qtavahiservice_p.h index e20c2e1a..7306d08a 100644 --- a/libguh/network/avahi/qtavahiservice_p.h +++ b/libguh/network/avahi/qtavahiservice_p.h @@ -46,6 +46,9 @@ public: quint16 port; QString type; int error; + + static AvahiStringList *createTxtList(const QHash &txt); + }; #endif // QTAVAHISERVICEPRIVATE_P diff --git a/libguh/network/avahi/qtavahiservicebrowser_p.cpp b/libguh/network/avahi/qtavahiservicebrowser_p.cpp index 6bfc8e26..18122db2 100644 --- a/libguh/network/avahi/qtavahiservicebrowser_p.cpp +++ b/libguh/network/avahi/qtavahiservicebrowser_p.cpp @@ -97,7 +97,7 @@ void QtAvahiServiceBrowserPrivate::callbackServiceBrowser(AvahiServiceBrowser *b // Remove the service foreach (const AvahiServiceEntry &entry, serviceBrowser->m_serviceEntries) { // Check not only the name, but also the protocol - if (entry.name() == name && entry.protocol() == QtAvahiServiceBrowserPrivate::converProtocol(protocol)) { + if (entry.name() == name && entry.protocol() == QtAvahiServiceBrowserPrivate::convertProtocol(protocol)) { serviceBrowser->m_serviceEntries.removeAll(entry); emit serviceBrowser->serviceEntryRemoved(entry); } @@ -146,8 +146,8 @@ void QtAvahiServiceBrowserPrivate::callbackServiceResolver(AvahiServiceResolver avahi_address_snprint(a, sizeof(a), address); // convert protocol - QAbstractSocket::NetworkLayerProtocol networkProtocol = QtAvahiServiceBrowserPrivate::converProtocol(protocol); - QStringList txtList = QtAvahiServiceBrowserPrivate::converTxtList(txt); + QAbstractSocket::NetworkLayerProtocol networkProtocol = QtAvahiServiceBrowserPrivate::convertProtocol(protocol); + QStringList txtList = QtAvahiServiceBrowserPrivate::convertTxtList(txt); // create the new resolved service entry AvahiServiceEntry entry = AvahiServiceEntry(name, @@ -168,7 +168,7 @@ void QtAvahiServiceBrowserPrivate::callbackServiceResolver(AvahiServiceResolver } -QStringList QtAvahiServiceBrowserPrivate::converTxtList(AvahiStringList *txt) +QStringList QtAvahiServiceBrowserPrivate::convertTxtList(AvahiStringList *txt) { if (!txt) return QStringList(); @@ -185,7 +185,7 @@ QStringList QtAvahiServiceBrowserPrivate::converTxtList(AvahiStringList *txt) return txtList; } -QAbstractSocket::NetworkLayerProtocol QtAvahiServiceBrowserPrivate::converProtocol(const AvahiProtocol &protocol) +QAbstractSocket::NetworkLayerProtocol QtAvahiServiceBrowserPrivate::convertProtocol(const AvahiProtocol &protocol) { QAbstractSocket::NetworkLayerProtocol networkProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; diff --git a/libguh/network/avahi/qtavahiservicebrowser_p.h b/libguh/network/avahi/qtavahiservicebrowser_p.h index cd8efbbc..c62322c1 100644 --- a/libguh/network/avahi/qtavahiservicebrowser_p.h +++ b/libguh/network/avahi/qtavahiservicebrowser_p.h @@ -68,8 +68,8 @@ public: void *userdata); // Convert members - static QStringList converTxtList(AvahiStringList *txt); - static QAbstractSocket::NetworkLayerProtocol converProtocol(const AvahiProtocol &protocol); + static QStringList convertTxtList(AvahiStringList *txt); + static QAbstractSocket::NetworkLayerProtocol convertProtocol(const AvahiProtocol &protocol); QtAvahiClient *client; AvahiServiceTypeBrowser *serviceTypeBrowser; diff --git a/server/jsonrpc/configurationhandler.cpp b/server/jsonrpc/configurationhandler.cpp index dd93c2be..e41062e5 100644 --- a/server/jsonrpc/configurationhandler.cpp +++ b/server/jsonrpc/configurationhandler.cpp @@ -112,6 +112,18 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): params.insert("port", JsonTypes::basicTypeToString(JsonTypes::Uint)); setParams("TcpServerConfigurationChanged", params); + params.clear(); returns.clear(); + setDescription("WebServerConfigurationChanged", "Emitted whenever the web server configuration changes."); + params.insert("host", JsonTypes::basicTypeToString(JsonTypes::String)); + params.insert("port", JsonTypes::basicTypeToString(JsonTypes::Uint)); + setParams("WebServerConfigurationChanged", params); + + params.clear(); returns.clear(); + setDescription("WebSocketServerConfigurationChanged", "Emitted whenever the web socket server configuration changes."); + params.insert("host", JsonTypes::basicTypeToString(JsonTypes::String)); + params.insert("port", JsonTypes::basicTypeToString(JsonTypes::Uint)); + setParams("WebSocketServerConfigurationChanged", params); + connect(GuhCore::instance()->configuration(), &GuhConfiguration::timeZoneChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(GuhCore::instance()->configuration(), &GuhConfiguration::serverNameChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(GuhCore::instance()->configuration(), &GuhConfiguration::tcpServerConfigurationChanged, this, &ConfigurationHandler::onTcpServerConfigurationChanged); diff --git a/server/jsonrpc/jsonrpcserver.cpp b/server/jsonrpc/jsonrpcserver.cpp index 4b888d9b..74b8b02f 100644 --- a/server/jsonrpc/jsonrpcserver.cpp +++ b/server/jsonrpc/jsonrpcserver.cpp @@ -156,7 +156,9 @@ void JsonRPCServer::registerTransportInterface(TransportInterface *interface) connect(interface, SIGNAL(clientConnected(const QUuid &)), this, SLOT(clientConnected(const QUuid &))); connect(interface, SIGNAL(clientDisconnected(const QUuid &)), this, SLOT(clientDisconnected(const QUuid &))); connect(interface, SIGNAL(dataAvailable(QUuid, QString, QString, QVariantMap)), this, SLOT(processData(QUuid, QString, QString, QVariantMap))); - interface->startServer(); + + QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection); + m_interfaces.append(interface); } diff --git a/server/rest/restserver.cpp b/server/rest/restserver.cpp index ffe7eac3..c7617da6 100644 --- a/server/rest/restserver.cpp +++ b/server/rest/restserver.cpp @@ -62,7 +62,7 @@ void RestServer::registerWebserver(WebServer *webServer) connect(m_webserver, &WebServer::clientDisconnected, this, &RestServer::clientDisconnected); connect(m_webserver, &WebServer::httpRequestReady, this, &RestServer::processHttpRequest); - m_webserver->startServer(); + QMetaObject::invokeMethod(m_webserver, "startServer", Qt::QueuedConnection); } void RestServer::setup() diff --git a/server/servermanager.cpp b/server/servermanager.cpp index 31f38d75..5b86ce71 100644 --- a/server/servermanager.cpp +++ b/server/servermanager.cpp @@ -70,10 +70,8 @@ ServerManager::ServerManager(QObject *parent) : } } - qCDebug(dcApplication) << "Starting JSON RPC Server"; m_jsonServer = new JsonRPCServer(m_sslConfiguration, this); - qCDebug(dcApplication) << "Starting REST Server"; m_restServer = new RestServer(m_sslConfiguration, this); } diff --git a/server/tcpserver.cpp b/server/tcpserver.cpp index 8c6b9432..a894b687 100644 --- a/server/tcpserver.cpp +++ b/server/tcpserver.cpp @@ -186,7 +186,14 @@ bool TcpServer::startServer() } #ifndef TESTING_ENABLED - m_avahiService->registerService("guhIO", m_port, "_jsonrpc._tcp"); + // Note: reversed order + QHash txt; + txt.insert("jsonrpcVersion", JSON_PROTOCOL_VERSION); + txt.insert("serverVersion", GUH_VERSION_STRING); + txt.insert("manufacturer", "guh GmbH"); + txt.insert("uuid", GuhCore::instance()->configuration()->serverUuid().toString()); + txt.insert("name", GuhCore::instance()->configuration()->serverName()); + m_avahiService->registerService("guhIO", m_port, "_jsonrpc._tcp", txt); #endif qCDebug(dcConnection) << "Started Tcp server on" << m_server->serverAddress().toString() << m_server->serverPort(); diff --git a/server/webserver.cpp b/server/webserver.cpp index 78a3179f..9c1b9fb9 100644 --- a/server/webserver.cpp +++ b/server/webserver.cpp @@ -560,7 +560,15 @@ bool WebServer::startServer() } #ifndef TESTING_ENABLED - m_avahiService->registerService("guhIO", m_port); + // Note: reversed order + QHash txt; + txt.insert("sslEnabled", GuhCore::instance()->configuration()->sslEnabled() ? "true" : "false"); + txt.insert("jsonrpcVersion", JSON_PROTOCOL_VERSION); + txt.insert("serverVersion", GUH_VERSION_STRING); + txt.insert("manufacturer", "guh GmbH"); + txt.insert("uuid", GuhCore::instance()->configuration()->serverUuid().toString()); + txt.insert("name", GuhCore::instance()->configuration()->serverName()); + m_avahiService->registerService("guhIO", m_port, "_http._tcp", txt); #endif m_enabled = true; diff --git a/server/websocketserver.cpp b/server/websocketserver.cpp index f294d900..297e9a3a 100644 --- a/server/websocketserver.cpp +++ b/server/websocketserver.cpp @@ -47,8 +47,9 @@ \sa WebServer, TcpServer, TransportInterface */ -#include "websocketserver.h" #include "guhsettings.h" +#include "guhcore.h" +#include "websocketserver.h" #include "loggingcategories.h" #include @@ -180,10 +181,14 @@ void WebSocketServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiSe bool WebSocketServer::reconfigureServer(const QHostAddress &address, const uint &port) { - if (m_host == address && m_port == (qint16)port && m_server->isListening()) + if (m_host == address && m_port == (qint16)port && m_server->isListening()) { + qCDebug(dcWebSocketServer()) << "Configuration unchanged. Not restarting the server."; return true; + } stopServer(); + qCDebug(dcWebSocketServer()) << "Stopped server for reconfiguration."; + QWebSocketServer *server; if (m_useSsl) { server = new QWebSocketServer("guh", QWebSocketServer::SecureMode, this); @@ -207,6 +212,7 @@ bool WebSocketServer::reconfigureServer(const QHostAddress &address, const uint // Start server with new configuration m_host = address; m_port = port; + qCDebug(dcWebSocketServer()) << "Restart server with new configuration."; return startServer(); } @@ -237,7 +243,15 @@ bool WebSocketServer::startServer() } #ifndef TESTING_ENABLED - m_avahiService->registerService("guhIO", m_port, "_ws._tcp"); + // Note: reversed order + QHash txt; + txt.insert("sslEnabled", GuhCore::instance()->configuration()->sslEnabled() ? "true" : "false"); + txt.insert("jsonrpcVersion", JSON_PROTOCOL_VERSION); + txt.insert("serverVersion", GUH_VERSION_STRING); + txt.insert("manufacturer", "guh GmbH"); + txt.insert("uuid", GuhCore::instance()->configuration()->serverUuid().toString()); + txt.insert("name", GuhCore::instance()->configuration()->serverName()); + m_avahiService->registerService("guhIO", m_port, "_ws._tcp", txt); #endif return true; diff --git a/tests/auto/api.json b/tests/auto/api.json index e0bc5b79..53828620 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -43 +44 { "methods": { "Actions.ExecuteAction": { @@ -586,8 +586,6 @@ } }, "notifications": { -<<<<<<< HEAD -======= "Cloud.ConnectionStatusChanged": { "description": "Emitted whenever the status of the cloud connection changed. The cloud connection is active if a cloud client is talking with the server.", "params": { @@ -613,7 +611,20 @@ "port": "Uint" } }, ->>>>>>> bump api and guhd version + "Configuration.WebServerConfigurationChanged": { + "description": "Emitted whenever the web server configuration changes.", + "params": { + "host": "String", + "port": "Uint" + } + }, + "Configuration.WebSocketServerConfigurationChanged": { + "description": "Emitted whenever the web socket server configuration changes.", + "params": { + "host": "String", + "port": "Uint" + } + }, "Devices.DeviceAdded": { "description": "Emitted whenever a Device was added.", "params": {