diff --git a/debian/control b/debian/control index 617d1184..49137f05 100644 --- a/debian/control +++ b/debian/control @@ -20,8 +20,6 @@ Build-Depends: debhelper (>= 9.0.0), libqt5bluetooth5, libqt5sql5-sqlite, libqt5dbus5, - libavahi-client-dev, - libavahi-common-dev, libssl-dev, libnymea-mqtt-dev, dbus-test-runner, @@ -57,7 +55,6 @@ Depends: libqt5network5, libqt5bluetooth5, libqt5sql5-sqlite, logrotate, - avahi-daemon, bluez, tar, iputils-tracepath, @@ -71,6 +68,7 @@ Recommends: nymea-cli, network-manager, nymea-update-plugin-impl, nymea-system-plugin-impl, + nymea-zeroconf-plugin-impl, Replaces: guhd Description: An open source IoT server - daemon The nymea daemon is a plugin based IoT (Internet of Things) server. The @@ -157,8 +155,6 @@ Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends}, libqt5bluetooth5, - libavahi-client3, - libavahi-common3 Replaces: libguh1 Description: An open source IoT server - core library The nymea daemon is a plugin based IoT (Internet of Things) server. The @@ -182,8 +178,6 @@ Depends: libnymea1 (= ${binary:Version}), qtconnectivity5-dev, qttools5-dev-tools, libqt5websockets5-dev, - libavahi-client-dev, - libavahi-common-dev Replaces: libguh1-dev Description: An open source IoT server - development files The nymea daemon is a plugin based IoT (Internet of Things) server. The diff --git a/debian/man/nymead.1 b/debian/man/nymead.1 index 8c71ecd4..10636c6e 100644 --- a/debian/man/nymead.1 +++ b/debian/man/nymead.1 @@ -47,8 +47,8 @@ Print the debug messages from the AWS connection. Print the debug messages from the AWS connection traffic. .IP \fIApplication\fR\ (default\ enabled) Print the debug messages from the core application. -.IP \fIAvahi\fR\ (default\ disabled) -Print the debug messages from the avahi resource. +.IP \fIPlatformZeroConfi\fR\ (default\ disabled) +Print the debug messages from the ZeroConf resource. .IP \fIBluetooth\fR\ (default\ disabled) Print the debug messages from the bluetooth resource. .IP \fICloud\fR\ (default\ enabled) diff --git a/libnymea-core/hardware/network/avahi/qt-watch.cpp b/libnymea-core/hardware/network/avahi/qt-watch.cpp deleted file mode 100644 index 6bca5789..00000000 --- a/libnymea-core/hardware/network/avahi/qt-watch.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/*** - This file is part of avahi. - - avahi is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - avahi is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General - Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with avahi; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. - - Modified: (C) 2016 Simon Stürz - -***/ - -#include -#include -#include - -#include -#include - -#include "qt-watch.h" - -class AvahiWatch : public QObject -{ - Q_OBJECT -public: - AvahiWatch(int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void* userdata); - ~AvahiWatch() { } - AvahiWatchEvent getEvents() const { return m_incallback ? m_lastEvent : (AvahiWatchEvent)0; } - void setWatchedEvents(AvahiWatchEvent event); - -private slots: - void gotIn(); - void gotOut(); - -private: - QSocketNotifier* m_in; - QSocketNotifier* m_out; - AvahiWatchCallback m_callback; - AvahiWatchEvent m_lastEvent; - int m_fd; - void* m_userdata; - bool m_incallback; -}; - -class AvahiTimeout : public QObject -{ - Q_OBJECT - -public: - AvahiTimeout(const struct timeval* tv, AvahiTimeoutCallback callback, void* userdata); - ~AvahiTimeout() {} - void update(const struct timeval* tv); - -private slots: - void timeout(); - -private: - QTimer m_timer; - AvahiTimeoutCallback m_callback; - void* m_userdata; -}; - - - -AvahiWatch::AvahiWatch(int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void* userdata) : - m_in(0), - m_out(0), - m_callback(callback), - m_fd(fd), - m_userdata(userdata), - m_incallback(false) -{ - setWatchedEvents(event); -} - -void AvahiWatch::gotIn() -{ - m_lastEvent = AVAHI_WATCH_IN; - m_incallback = true; - m_callback(this, m_fd, m_lastEvent, m_userdata); - m_incallback = false; -} - -void AvahiWatch::gotOut() -{ - m_lastEvent = AVAHI_WATCH_OUT; - m_incallback = true; - m_callback(this, m_fd, m_lastEvent, m_userdata); - m_incallback = false; -} - -void AvahiWatch::setWatchedEvents(AvahiWatchEvent event) -{ - if (!(event & AVAHI_WATCH_IN)) { delete m_in; m_in = 0; } - if (!(event & AVAHI_WATCH_OUT)) { delete m_out; m_out = 0; } - if (event & AVAHI_WATCH_IN) { - m_in = new QSocketNotifier(m_fd,QSocketNotifier::Read, this); - connect(m_in, SIGNAL(activated(int)), SLOT(gotIn())); - } - if (event & AVAHI_WATCH_OUT) { - m_out = new QSocketNotifier(m_fd, QSocketNotifier::Write, this); - connect(m_out, SIGNAL(activated(int)), SLOT(gotOut())); - } -} - -AvahiTimeout::AvahiTimeout(const struct timeval* tv, AvahiTimeoutCallback callback, void *userdata) : - m_callback(callback), - m_userdata(userdata) -{ - connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeout())); - m_timer.setSingleShot(true); - update(tv); -} - -void AvahiTimeout::update(const struct timeval *tv) -{ - m_timer.stop(); - if (tv) { - AvahiUsec u = avahi_age(tv)/1000; - m_timer.start( (u>0) ? 0 : -u); - } -} - -void AvahiTimeout::timeout() -{ - m_callback(this, m_userdata); -} - -static AvahiWatch* q_watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) -{ - Q_UNUSED(api) - return new AvahiWatch(fd, event, callback, userdata); -} - -static void q_watch_update(AvahiWatch *w, AvahiWatchEvent events) -{ - w->setWatchedEvents(events); -} - -static AvahiWatchEvent q_watch_get_events(AvahiWatch *w) -{ - return w->getEvents(); -} - -static void q_watch_free(AvahiWatch *w) -{ - delete w; -} - -static AvahiTimeout* q_timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) -{ - Q_UNUSED(api) - return new AvahiTimeout(tv, callback, userdata); -} - -static void q_timeout_update(AvahiTimeout *t, const struct timeval *tv) -{ - t->update(tv); -} - -static void q_timeout_free(AvahiTimeout *t) -{ - delete t; -} - -const AvahiPoll* avahi_qt_poll_get(void) -{ - static const AvahiPoll qt_poll = { - NULL, - q_watch_new, - q_watch_update, - q_watch_get_events, - q_watch_free, - q_timeout_new, - q_timeout_update, - q_timeout_free - }; - - return &qt_poll; -} - -#include "qt-watch.moc" - diff --git a/libnymea-core/hardware/network/avahi/qt-watch.h b/libnymea-core/hardware/network/avahi/qt-watch.h deleted file mode 100644 index ea5c1fc5..00000000 --- a/libnymea-core/hardware/network/avahi/qt-watch.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef QAVAHI_H -#define QAVAHI_H - -/*** - This file is part of avahi. - - avahi is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - avahi is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General - Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with avahi; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. - - Modified: (C) 2016 Simon Stürz - -***/ - -/** \file qt-watch.h Qt main loop adapter */ - -#include - -AVAHI_C_DECL_BEGIN - -/** Setup abstract poll structure for integration with Qt main loop */ -const AvahiPoll* avahi_qt_poll_get(void); - -AVAHI_C_DECL_END - -#endif // QAVAHI_H diff --git a/libnymea-core/hardware/network/avahi/qtavahiclient.cpp b/libnymea-core/hardware/network/avahi/qtavahiclient.cpp deleted file mode 100644 index edd9a374..00000000 --- a/libnymea-core/hardware/network/avahi/qtavahiclient.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "qt-watch.h" -#include "qtavahiclient.h" -#include "loggingcategories.h" - -#include "qtavahiservicebrowserimplementation.h" -#include "qtavahiservicebrowserimplementation_p.h" - -#include - -namespace nymeaserver { - -QtAvahiClient::QtAvahiClient(QObject *parent) : - QObject(parent), - m_poll(avahi_qt_poll_get()), - m_client(nullptr), - error(0), - m_state(QtAvahiClientStateNone) -{ - connect(this, &QtAvahiClient::clientStateChangedInternal, this, &QtAvahiClient::onClientStateChanged); -} - -QtAvahiClient::~QtAvahiClient() -{ - if (m_client) - avahi_client_free(m_client); - -} - -QtAvahiClient::QtAvahiClientState QtAvahiClient::state() const -{ - return m_state; -} - -void QtAvahiClient::start() -{ - if (m_client) - return; - - m_client = avahi_client_new(m_poll, (AvahiClientFlags) 0, QtAvahiClient::callback, this, &error); -} - -void QtAvahiClient::stop() -{ - if (m_client) - avahi_client_free(m_client); - - m_client = nullptr; -} - -QString QtAvahiClient::errorString() const -{ - return QString(avahi_strerror(error)); -} - -void QtAvahiClient::callback(AvahiClient *client, AvahiClientState state, void *userdata) -{ - QtAvahiClient *serviceClient = static_cast(userdata); - if (!serviceClient) - return; - - serviceClient->m_client = client; - - switch (state) { - case AVAHI_CLIENT_S_RUNNING: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateRunning); - break; - case AVAHI_CLIENT_FAILURE: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateFailure); - break; - case AVAHI_CLIENT_S_COLLISION: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateCollision); - break; - case AVAHI_CLIENT_S_REGISTERING: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateRegistering); - break; - case AVAHI_CLIENT_CONNECTING: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateConnecting); - break; - } -} - -void QtAvahiClient::onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state) -{ - if (m_state == state) - return; - - m_state = state; - -// switch (m_state) { -// case QtAvahiClientStateNone: -// break; -// case QtAvahiClientStateRunning: -// qCDebug(dcAvahi()) << "Client running."; -// break; -// case QtAvahiClientStateFailure: -// qCWarning(dcAvahi()) << "Client failure:" << errorString(); -// break; -// case QtAvahiClientStateCollision: -// qCWarning(dcAvahi()) << "Client collision:" << errorString(); -// break; -// case QtAvahiClientStateRegistering: -// qCDebug(dcAvahi()) << "Client registering..."; -// break; -// case QtAvahiClientStateConnecting: -// qCDebug(dcAvahi()) << "Client connecting..."; -// break; -// default: -// break; -// } - - emit clientStateChanged(m_state); -} - -} diff --git a/libnymea-core/hardware/network/avahi/qtavahiservice.cpp b/libnymea-core/hardware/network/avahi/qtavahiservice.cpp deleted file mode 100644 index 70ebe537..00000000 --- a/libnymea-core/hardware/network/avahi/qtavahiservice.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*! - \class nymeaserver::QtAvahiService - \brief Allows to publish an avahi service to the network. - - \inmodule core -*/ - -/*! \enum QtAvahiService::QtAvahiServiceState - - This enum type specifies the state of a \l{QtAvahiService}. - - \value QtAvahiServiceStateUncomitted - The group has not yet been committed, the user must still call avahi_entry_group_commit(). - \value QtAvahiServiceStateRegistering - The entries of the group are currently being registered. - \value QtAvahiServiceStateEstablished - The entries have successfully been established. - \value QtAvahiServiceStateCollision - A name collision for one of the entries in the group has been detected, the entries have been withdrawn. - \value QtAvahiServiceStateFailure - Some kind of failure happened, the entries have been withdrawn. - -*/ - -/*! \fn void QtAvahiService::serviceStateChanged(const QtAvahiServiceState &state) - This signal will be emitted when the \a state of this \l{QtAvahiService} has changed. -*/ - -#include "qtavahiservice.h" -#include "qtavahiservice_p.h" -#include "loggingcategories.h" - -#include -#include - -namespace nymeaserver { - -/*! Constructs a new QtAvahiService with the given \a parent. */ -QtAvahiService::QtAvahiService(QObject *parent) : - QObject(parent), - d_ptr(new QtAvahiServicePrivate), - m_state(QtAvahiServiceStateUncommitted) -{ - connect(this, &QtAvahiService::serviceStateChanged, this, &QtAvahiService::onStateChanged); - - d_ptr->client = new QtAvahiClient(this); - d_ptr->client->start(); - - m_reregisterTimer.setInterval(60000); - m_reregisterTimer.setSingleShot(true); - connect(&m_reregisterTimer, &QTimer::timeout, this, [this](){ - qCDebug(dcAvahiDebug()) << "Re-registering service" << this; - resetService(true); - registerService(m_name, m_hostAddress, m_port, m_serviceType, m_txtRecords, true); - }); -} - -/*! Destructs this \l{QtAvahiService}. */ -QtAvahiService::~QtAvahiService() -{ - if (d_ptr->group) { - if (d_ptr->serviceList) { - avahi_string_list_free(d_ptr->serviceList); - } - avahi_entry_group_free(d_ptr->group); - } - - delete d_ptr; -} - -/*! Returns the hostAddress of this \l{QtAvahiService}. */ -QHostAddress QtAvahiService::hostAddress() const -{ - return d_ptr->hostAddress; -} - -/*! Returns the port of this \l{QtAvahiService}. */ -quint16 QtAvahiService::port() const -{ - return d_ptr->port; -} - -/*! Returns the name of this \l{QtAvahiService}. */ -QString QtAvahiService::name() const -{ - return d_ptr->name; -} - -/*! Returns the service type of this \l{QtAvahiService}. */ -QString QtAvahiService::serviceType() const -{ - return d_ptr->type; -} - -QHash QtAvahiService::txtRecords() const -{ - return d_ptr->txtRecords; -} - -QtAvahiService::QtAvahiServiceState QtAvahiService::state() const -{ - return m_state; -} - -/*! Register a new \l{QtAvahiService} with the given \a name and \a port. The service type can be specified with the \a serviceType string. The \a txtRecords records inform about additional information. Returns true if the service could be registered. */ -bool QtAvahiService::registerService(const QString &name, const QHostAddress &hostAddress, const quint16 &port, const QString &serviceType, const QHash &txtRecords, bool silent) -{ - // Check if the client is running - if (!d_ptr->client->m_client || AVAHI_CLIENT_S_RUNNING != avahi_client_get_state(d_ptr->client->m_client)) { - qCWarning(dcAvahi()) << "Could not register service" << name << port << serviceType << ". The client is not available."; - return false; - } - - // Cache all values locally at first - m_name = name; - m_hostAddress = hostAddress; - m_port = port; - m_serviceType = serviceType; - m_txtRecords = txtRecords; - - // Now set up avahi - d_ptr->name = name; - d_ptr->hostAddress = hostAddress; - d_ptr->port = port; - d_ptr->type = serviceType; - d_ptr->txtRecords = txtRecords; - - // If the group is not set yet, create it - if (!d_ptr->group) - d_ptr->group = avahi_entry_group_new(d_ptr->client->m_client, QtAvahiServicePrivate::callback, this); - - // If the group is empty - if (avahi_entry_group_is_empty(d_ptr->group)) { - // Add the service - AvahiIfIndex ifIndex = AVAHI_IF_UNSPEC; - if (hostAddress != QHostAddress("0.0.0.0")) { - foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { - foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) { - QPair subnet = QHostAddress::parseSubnet(addressEntry.ip().toString() + "/" + addressEntry.netmask().toString()); - if (hostAddress.isInSubnet(subnet.first, subnet.second)) { - ifIndex = interface.index(); - break; - } - } - } - } - - qCDebug((silent ? dcAvahiDebug() : dcAvahi())) << "Registering avahi service" << name << hostAddress.toString() << port << serviceType << "on interface" << ifIndex; - - d_ptr->serviceList = QtAvahiServicePrivate::createTxtList(txtRecords); - d_ptr->error = avahi_entry_group_add_service_strlst(d_ptr->group, - ifIndex, - hostAddress.protocol() == QAbstractSocket::IPv6Protocol ? AVAHI_PROTO_INET6 : AVAHI_PROTO_INET, - (AvahiPublishFlags) 0, - d_ptr->name.toLatin1().data(), - d_ptr->type.toLatin1().data(), - 0, - 0, - (uint16_t)d_ptr->port, - d_ptr->serviceList); - - // Verify if the group has to be comitted - if (d_ptr->error) { - - if (d_ptr->error == AVAHI_ERR_COLLISION) { - if (!handleCollision()) { - qCWarning(dcAvahi()) << this << "error:" << avahi_strerror(d_ptr->error); - return false; - } - - - } else { - qCWarning(dcAvahi()) << this << "error:" << avahi_strerror(d_ptr->error); - return false; - } - } - - // Commit the service - d_ptr->error = avahi_entry_group_commit(d_ptr->group); - if (d_ptr->error) { - qCWarning(dcAvahi()) << this << "error:" << avahi_strerror(d_ptr->error); - return false; - } - } else { - qCWarning(dcAvahi()) << "Service already registered. Please reset the service before reusing it."; - return false; - } - - // Reregister every minute in order to work around low quality network hardware which - // doesn't properly keep multicast sessions alive. - // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=736641 - m_reregisterTimer.start(); - return true; -} - -/*! Remove this service from the local network. This \l{QtAvahiService} can be reused to register a new avahi service. */ -void QtAvahiService::resetService(bool silent) -{ - if (!d_ptr->group) { - qCWarning(dcAvahi()) << "Cannot unregister service. Service Group not existing."; - return; - } - - qCDebug((silent ? dcAvahiDebug() : dcAvahi())) << "Unregistering service" << this; - - if (d_ptr->serviceList) { - avahi_string_list_free(d_ptr->serviceList); - d_ptr->serviceList = nullptr; - } - avahi_entry_group_reset(d_ptr->group); - m_reregisterTimer.stop(); -} - -/*! Update the TXT record of this service. Returns true of the record could be updated. */ -bool QtAvahiService::updateTxtRecord(const QHash &txtRecords) -{ - if (!d_ptr->group) - return false; - - m_txtRecords = txtRecords; - - // Add the service - AvahiIfIndex ifIndex = AVAHI_IF_UNSPEC; - if (d_ptr->hostAddress != QHostAddress("0.0.0.0")) { - foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { - foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) { - QPair subnet = QHostAddress::parseSubnet(addressEntry.ip().toString() + "/" + addressEntry.netmask().toString()); - if (d_ptr->hostAddress.isInSubnet(subnet.first, subnet.second)) { - ifIndex = interface.index(); - break; - } - } - } - } - - d_ptr->serviceList = QtAvahiServicePrivate::createTxtList(txtRecords); - d_ptr->error = avahi_entry_group_update_service_txt_strlst(d_ptr->group, - ifIndex, - d_ptr->hostAddress.protocol() == QAbstractSocket::IPv6Protocol ? AVAHI_PROTO_INET6 : AVAHI_PROTO_INET, - (AvahiPublishFlags) 0, - d_ptr->name.toLatin1().data(), - d_ptr->type.toLatin1().data(), - 0, - d_ptr->serviceList); - - // Verify if the group has to be comitted - if (d_ptr->error) { - qCWarning(dcAvahi()) << this << "error:" << avahi_strerror(d_ptr->error); - return false; - } - - qCDebug(dcAvahi()) << this << "updated TXT record."; - - return true; -} - -/*! Returns true if the service group was added and committed to the network without errors. */ -bool QtAvahiService::isValid() const -{ - return (d_ptr->group && !d_ptr->error); -} - -/*! Returns the error string of this \l{QtAvahiService}. */ -QString QtAvahiService::errorString() const -{ - if (!d_ptr->client->m_client) - return "Invalid client."; - - return avahi_strerror(avahi_client_errno(d_ptr->client->m_client)); -} - -bool QtAvahiService::handleCollision() -{ - char* alt = avahi_alternative_service_name(name().toStdString().data()); - QString alternativeServiceName = QLatin1String(alt); - free(alt); - qCDebug(dcAvahi()) << "Service name collision. Picking alternative service name" << alternativeServiceName; - - resetService(); - return registerService(alternativeServiceName, hostAddress(), port(), serviceType(), txtRecords()); -} - -void QtAvahiService::onStateChanged(const QtAvahiServiceState &state) -{ - if (m_state == state) - return; - - m_state = state; - - switch (m_state) { - case QtAvahiServiceStateUncommitted: - qCDebug(dcAvahiDebug()) << "Service state changed to Uncommitted:" << this; - break; - case QtAvahiServiceStateRegistering: - qCDebug(dcAvahiDebug()) << "Service state changed to Registering:" << this; - break; - case QtAvahiServiceStateEstablished: - qCDebug(dcAvahiDebug()) << "Service state changed to Established:" << this; - break; - case QtAvahiServiceStateCollision: - qCDebug(dcAvahiDebug()) << "Service state changed to Collision:" << this; - handleCollision(); - break; - case QtAvahiServiceStateFailure: - qCDebug(dcAvahiDebug()) << "Service state changed to Failure:" << this; - break; - } - -} - -QDebug operator <<(QDebug dbg, QtAvahiService *service) -{ - dbg.nospace() << "AvahiService("; - dbg << service->name() << ", " << service->serviceType() << ", " << service->port() << ") "; - return dbg; -} - -} diff --git a/libnymea-core/hardware/network/avahi/qtavahiservice.h b/libnymea-core/hardware/network/avahi/qtavahiservice.h deleted file mode 100644 index 962db1fc..00000000 --- a/libnymea-core/hardware/network/avahi/qtavahiservice.h +++ /dev/null @@ -1,96 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef QTAVAHISERVICE_H -#define QTAVAHISERVICE_H - -#include -#include -#include -#include -#include - -namespace nymeaserver { - -class QtAvahiServicePrivate; - -class QtAvahiService : public QObject -{ - Q_OBJECT - -public: - enum QtAvahiServiceState { - QtAvahiServiceStateUncommitted = 0, - QtAvahiServiceStateRegistering = 1, - QtAvahiServiceStateEstablished = 2, - QtAvahiServiceStateCollision = 3, - QtAvahiServiceStateFailure = 4 - }; - Q_ENUM(QtAvahiServiceState) - - explicit QtAvahiService(QObject *parent = nullptr); - ~QtAvahiService(); - - QHostAddress hostAddress() const; - quint16 port() const; - QString name() const; - QString serviceType() const; - QHash txtRecords() const; - QtAvahiServiceState state() const; - - bool registerService(const QString &name, const QHostAddress &hostAddress, const quint16 &port, const QString &serviceType = "_http._tcp", const QHash &txtRecords = QHash(), bool silent = false); - void resetService(bool silent = false); - - bool updateTxtRecord(const QHash &txtRecords); - - bool isValid() const; - QString errorString() const; - -signals: - void serviceStateChanged(const QtAvahiServiceState &state); - -protected: - QtAvahiServicePrivate *d_ptr; - -private slots: - bool handleCollision(); - void onStateChanged(const QtAvahiServiceState &state); - -private: - QtAvahiServiceState m_state; - Q_DECLARE_PRIVATE(QtAvahiService) - - QTimer m_reregisterTimer; - - QString m_name; - QHostAddress m_hostAddress; - quint16 m_port; - QString m_serviceType; - QHash m_txtRecords; -}; - -QDebug operator <<(QDebug dbg, QtAvahiService *service); - -} - -#endif // QTAVAHISERVICE_H diff --git a/libnymea-core/hardware/network/avahi/qtavahiservice_p.cpp b/libnymea-core/hardware/network/avahi/qtavahiservice_p.cpp deleted file mode 100644 index 431e0494..00000000 --- a/libnymea-core/hardware/network/avahi/qtavahiservice_p.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "qtavahiservice_p.h" -#include "loggingcategories.h" - -#include -#include -#include - -namespace nymeaserver { - -QtAvahiServicePrivate::QtAvahiServicePrivate() : - client(0), - group(0), - error(0) -{ - -} - -void QtAvahiServicePrivate::callback(AvahiEntryGroup *group, AvahiEntryGroupState state, void *userdata) -{ - Q_UNUSED(group); - - QtAvahiService *service = static_cast(userdata); - if (!service) - return; - - if (service->state() == (QtAvahiService::QtAvahiServiceState)state) - return; - - switch (state) { - case AVAHI_ENTRY_GROUP_UNCOMMITED: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateUncommitted); - break; - case AVAHI_ENTRY_GROUP_REGISTERING: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateRegistering); - break; - case AVAHI_ENTRY_GROUP_ESTABLISHED: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateEstablished); - break; - case AVAHI_ENTRY_GROUP_COLLISION: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateCollision); - break; - case AVAHI_ENTRY_GROUP_FAILURE: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateFailure); - break; - } -} - -AvahiStringList *QtAvahiServicePrivate::createTxtList(const QHash &txt) -{ - AvahiStringList *list = nullptr; - 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/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation.cpp b/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation.cpp deleted file mode 100644 index a92560eb..00000000 --- a/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*! - \class nymeaserver::QtAvahiServiceBrowserImplementation - \brief Allows to browse avahi services in the local network. - - \ingroup hardware - \inmodule libnymea -*/ - -#include "qtavahiservicebrowserimplementation.h" -#include "qtavahiservicebrowserimplementation_p.h" -#include "loggingcategories.h" - -#include - -namespace nymeaserver { - -/*! Constructs a new \l{QtAvahiServiceBrowserImplementation} with the given \a parent. */ -QtAvahiServiceBrowserImplementation::QtAvahiServiceBrowserImplementation(QObject *parent) : - QtAvahiServiceBrowser(parent), - d_ptr(new QtAvahiServiceBrowserImplementationPrivate(new QtAvahiClient)) -{ - // TODO: check available here - m_available = true; - - connect(d_ptr->client, &QtAvahiClient::clientStateChanged, this, &QtAvahiServiceBrowserImplementation::onClientStateChanged); - - qCDebug(dcAvahiDebug()) << "-->" << name() << "created successfully."; -} - -/*! Destructs this \l{QtAvahiServiceBrowserImplementation}. */ -QtAvahiServiceBrowserImplementation::~QtAvahiServiceBrowserImplementation() -{ - // Delete each service browser - foreach (const QString &serviceType, d_ptr->serviceBrowserTable.keys()) { - AvahiServiceBrowser *browser = d_ptr->serviceBrowserTable.take(serviceType); - if (browser) { - avahi_service_browser_free(browser); - } - } - - // Delete the service type browser - if (d_ptr->serviceTypeBrowser) - avahi_service_type_browser_free(d_ptr->serviceTypeBrowser); - - delete d_ptr; -} - -/*! Returns the current \l{AvahiServiceEntry} list of this \l{QtAvahiServiceBrowserImplementation}. */ -QList QtAvahiServiceBrowserImplementation::serviceEntries() const -{ - return m_serviceEntries; -} - -bool QtAvahiServiceBrowserImplementation::available() const -{ - return m_available; -} - -bool QtAvahiServiceBrowserImplementation::enabled() const -{ - return m_enabled; -} - -void QtAvahiServiceBrowserImplementation::onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state) -{ - if (state == QtAvahiClient::QtAvahiClientStateRunning) { - qCDebug(dcAvahiDebug()) << "Service browser client connected."; - // Return if we already have a service type browser - if (d_ptr->serviceTypeBrowser) - return; - - d_ptr->serviceTypeBrowser = avahi_service_type_browser_new(d_ptr->client->m_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, (AvahiLookupFlags) 0, QtAvahiServiceBrowserImplementationPrivate::callbackServiceTypeBrowser, this); - } else if (state == QtAvahiClient::QtAvahiClientStateFailure) { - qCWarning(dcAvahi()) << name() << "client failure:" << d_ptr->client->errorString(); - } -} - -void QtAvahiServiceBrowserImplementation::setEnabled(bool enabled) -{ - if (m_enabled == enabled) { - qCDebug(dcAvahi()) << "Avahi Service Browser already" << (enabled ? "enabled" : "disabled") << "... Not changing state."; - return; - } - if (enabled) { - d_ptr->client->start(); - qCDebug(dcAvahi()) << "Avahi Service Browser enabled"; - } else { - d_ptr->client->stop(); - qCDebug(dcAvahi()) << "Avahi Service Browser disabled"; - } -} - -void QtAvahiServiceBrowserImplementation::createServiceBrowser(const char *serviceType) -{ - // create a new service browser for the given serviceType - AvahiServiceBrowser *browser = avahi_service_browser_new(d_ptr->client->m_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, serviceType, NULL, (AvahiLookupFlags) 0, QtAvahiServiceBrowserImplementationPrivate::callbackServiceBrowser, this); - d_ptr->serviceBrowserTable.insert(serviceType, browser); -} - -} diff --git a/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation_p.cpp b/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation_p.cpp deleted file mode 100644 index d35a6a6c..00000000 --- a/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation_p.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "qtavahiservicebrowserimplementation_p.h" -#include "qtavahiservicebrowserimplementation.h" -#include "network/avahi/avahiserviceentry.h" -#include "loggingcategories.h" - -#include -#include - -#include - -namespace nymeaserver { - -QtAvahiServiceBrowserImplementationPrivate::QtAvahiServiceBrowserImplementationPrivate(QtAvahiClient *client) : - client(client), - serviceTypeBrowser(nullptr) -{ - -} - -QtAvahiServiceBrowserImplementationPrivate::~QtAvahiServiceBrowserImplementationPrivate() -{ - foreach (AvahiServiceResolver *resolver, m_serviceResolvers) { - avahi_service_resolver_free(resolver); - } -} - -void QtAvahiServiceBrowserImplementationPrivate::callbackServiceTypeBrowser(AvahiServiceTypeBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata) -{ - Q_UNUSED(browser) - Q_UNUSED(interface) - Q_UNUSED(protocol) - Q_UNUSED(domain) - Q_UNUSED(flags) - - QtAvahiServiceBrowserImplementation *serviceBrowser = static_cast(userdata); - if (!serviceBrowser) - return; - - switch (event) { - case AVAHI_BROWSER_NEW: - if (!serviceBrowser->m_serviceTypes.contains(type)) { - serviceBrowser->m_serviceTypes.append(type); - qCDebug(dcAvahiDebug()) << "[+] Service browser" << type; - serviceBrowser->createServiceBrowser(type); - } - break; - case AVAHI_BROWSER_REMOVE: - // Note: the browser for this serviceType will be deleted once all - // services from this type are removed - break; - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - case AVAHI_BROWSER_ALL_FOR_NOW: - break; - case AVAHI_BROWSER_FAILURE: - qCWarning(dcAvahi()) << "Service type browser error:" << QString(avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->m_client))); - break; - } -} - -void QtAvahiServiceBrowserImplementationPrivate::callbackServiceBrowser(AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata) -{ - Q_UNUSED(browser); - Q_UNUSED(flags); - - QtAvahiServiceBrowserImplementation *serviceBrowser = static_cast(userdata); - if (!serviceBrowser) - return; - - switch (event) { - case AVAHI_BROWSER_NEW: { - // Start resolving new service - AvahiServiceResolver *resolver = avahi_service_resolver_new(serviceBrowser->d_ptr->client->m_client, - interface, - protocol, - name, - type, - domain, - AVAHI_PROTO_UNSPEC, - (AvahiLookupFlags) 0, - QtAvahiServiceBrowserImplementationPrivate::callbackServiceResolver, - serviceBrowser); - if (resolver) { - serviceBrowser->d_ptr->m_serviceResolvers.append(resolver); - } else { - qCWarning(dcAvahi()) << "Failed to resolve service" << QString(name) << ":" << avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->m_client)); - } - break; - } - case AVAHI_BROWSER_REMOVE: { - // 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() == QtAvahiServiceBrowserImplementationPrivate::convertProtocol(protocol)) { - serviceBrowser->m_serviceEntries.removeAll(entry); - emit serviceBrowser->serviceEntryRemoved(entry); - } - } - - // Check if this was the last service for this serviceType - foreach (const AvahiServiceEntry &entry, serviceBrowser->m_serviceEntries) { - if (entry.serviceType() == type) - return; - } - - // This was the last service for this serviceType, lets delete the corresponding browser - AvahiServiceBrowser *browser = serviceBrowser->d_ptr->serviceBrowserTable.take(type); - if (browser) - avahi_service_browser_free(browser); - - serviceBrowser->m_serviceTypes.removeAll(type); - break; - } - case AVAHI_BROWSER_ALL_FOR_NOW: - break; - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - case AVAHI_BROWSER_FAILURE: - qCWarning(dcAvahi()) << "Service browser error:" << QString(avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->m_client))); - break; - } - -} - -void QtAvahiServiceBrowserImplementationPrivate::callbackServiceResolver(AvahiServiceResolver *resolver, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) -{ - Q_UNUSED(interface); - Q_UNUSED(type); - Q_UNUSED(txt); - - QPointer serviceBrowser = static_cast(userdata); - if (serviceBrowser.isNull()) - return; - - switch (event) { - case AVAHI_RESOLVER_FAILURE: - break; - case AVAHI_RESOLVER_FOUND: { - char a[AVAHI_ADDRESS_STR_MAX]; - avahi_address_snprint(a, sizeof(a), address); - - // convert protocol - QAbstractSocket::NetworkLayerProtocol networkProtocol = QtAvahiServiceBrowserImplementationPrivate::convertProtocol(protocol); - QStringList txtList = QtAvahiServiceBrowserImplementationPrivate::convertTxtList(txt); - - // create the new resolved service entry - AvahiServiceEntry entry = AvahiServiceEntry(name, - type, - QHostAddress(QString(a)), - QString(domain), - QString(host_name), - (quint16)port, - networkProtocol, - txtList, - flags); - - serviceBrowser->m_serviceEntries.append(entry); - emit serviceBrowser->serviceEntryAdded(entry); - } - } - serviceBrowser->d_ptr->m_serviceResolvers.removeAll(resolver); - avahi_service_resolver_free(resolver); - -} - -QStringList QtAvahiServiceBrowserImplementationPrivate::convertTxtList(AvahiStringList *txt) -{ - if (!txt) - return QStringList(); - - QStringList txtList; - txtList.append(QString(reinterpret_cast(txt->text))); - - while (txt->next) { - AvahiStringList *next = txt->next; - txtList.append(QString(reinterpret_cast(next->text))); - txt = next; - } - - return txtList; -} - -QAbstractSocket::NetworkLayerProtocol QtAvahiServiceBrowserImplementationPrivate::convertProtocol(const AvahiProtocol &protocol) -{ - QAbstractSocket::NetworkLayerProtocol networkProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - - switch (protocol) { - case AVAHI_PROTO_INET: - networkProtocol = QAbstractSocket::IPv4Protocol; - break; - case AVAHI_PROTO_INET6: - networkProtocol = QAbstractSocket::IPv6Protocol; - break; - case AVAHI_PROTO_UNSPEC: - networkProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - break; - } - return networkProtocol; -} - -} diff --git a/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation_p.h b/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation_p.h deleted file mode 100644 index 945eb994..00000000 --- a/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef QTAVAHISERVICEBROWSERPRIVATE_H -#define QTAVAHISERVICEBROWSERPRIVATE_H - -#include -#include -#include - -#include "qtavahiclient.h" -#include "qtavahiservice.h" - - -namespace nymeaserver { - -class QtAvahiServiceTypeBrowserImplementation; - -class QtAvahiServiceBrowserImplementationPrivate -{ -public: - QtAvahiServiceBrowserImplementationPrivate(QtAvahiClient *client); - ~QtAvahiServiceBrowserImplementationPrivate(); - - // Callback members - static void callbackServiceTypeBrowser(AvahiServiceTypeBrowser *browser, - AvahiIfIndex interface, - AvahiProtocol protocol, - AvahiBrowserEvent event, - const char *type, - const char *domain, - AvahiLookupResultFlags flags, - void *userdata); - - static void callbackServiceBrowser(AvahiServiceBrowser *browser, - AvahiIfIndex interface, - AvahiProtocol protocol, - AvahiBrowserEvent event, - const char *name, - const char *type, - const char *domain, - AvahiLookupResultFlags flags, - void *userdata); - - static void callbackServiceResolver(AvahiServiceResolver *resolver, AvahiIfIndex interface, - AvahiProtocol protocol, - AvahiResolverEvent event, - const char *name, - const char *type, - const char *domain, - const char *host_name, - const AvahiAddress *address, - uint16_t port, - AvahiStringList *txt, - AvahiLookupResultFlags flags, - void *userdata); - - // Convert members - static QStringList convertTxtList(AvahiStringList *txt); - static QAbstractSocket::NetworkLayerProtocol convertProtocol(const AvahiProtocol &protocol); - - QtAvahiClient *client; - AvahiServiceTypeBrowser *serviceTypeBrowser; - QHash serviceBrowserTable; - QList m_serviceResolvers; -}; - -} - -#endif // QTAVAHISERVICEBROWSERPRIVATE_H diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp index 72533f0a..7d9061ce 100644 --- a/libnymea-core/hardwaremanagerimplementation.cpp +++ b/libnymea-core/hardwaremanagerimplementation.cpp @@ -22,19 +22,24 @@ #include "loggingcategories.h" +#include "platform/platform.h" + +#include "platform/platformzeroconfcontroller.h" +#include "network/zeroconf/zeroconfservicebrowser.h" + #include "hardwaremanagerimplementation.h" #include "hardware/plugintimermanagerimplementation.h" #include "hardware/network/upnp/upnpdiscoveryimplementation.h" #include "hardware/network/networkaccessmanagerimpl.h" #include "hardware/radio433/radio433brennenstuhl.h" #include "hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.h" -#include "hardware/network/avahi/qtavahiservicebrowserimplementation.h" #include "hardware/network/mqtt/mqttproviderimplementation.h" namespace nymeaserver { -HardwareManagerImplementation::HardwareManagerImplementation(MqttBroker *mqttBroker, QObject *parent) : - HardwareManager(parent) +HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, QObject *parent) : + HardwareManager(parent), + m_platform(platform) { // Create network access manager for all resources, centralized // Note: configuration and proxy settings could be implemented here @@ -52,9 +57,6 @@ HardwareManagerImplementation::HardwareManagerImplementation(MqttBroker *mqttBro // UPnP discovery m_upnpDiscovery = new UpnpDiscoveryImplementation(m_networkAccessManager, this); - // Avahi Browser - m_avahiBrowser = new QtAvahiServiceBrowserImplementation(this); - // Bluetooth LE m_bluetoothLowEnergyManager = new BluetoothLowEnergyManagerImplementation(m_pluginTimerManager->registerTimer(10), this); @@ -70,8 +72,8 @@ HardwareManagerImplementation::HardwareManagerImplementation(MqttBroker *mqttBro if (m_upnpDiscovery->available()) setResourceEnabled(m_upnpDiscovery, true); - if (m_avahiBrowser->available()) - setResourceEnabled(m_avahiBrowser, true); + if (m_platform->zeroConfController()->zeroConfServiceBrowser()->available()) + setResourceEnabled(m_platform->zeroConfController()->zeroConfServiceBrowser(), true); if (m_bluetoothLowEnergyManager->available()) setResourceEnabled(m_bluetoothLowEnergyManager, true); @@ -103,9 +105,9 @@ UpnpDiscovery *HardwareManagerImplementation::upnpDiscovery() return m_upnpDiscovery; } -QtAvahiServiceBrowser *HardwareManagerImplementation::avahiBrowser() +ZeroConfServiceBrowser *HardwareManagerImplementation::zeroConfServiceBrowser() { - return m_avahiBrowser; + return m_platform->zeroConfController()->zeroConfServiceBrowser(); } BluetoothLowEnergyManager *HardwareManagerImplementation::bluetoothLowEnergyManager() diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h index 8ff18dd2..b69df71b 100644 --- a/libnymea-core/hardwaremanagerimplementation.h +++ b/libnymea-core/hardwaremanagerimplementation.h @@ -34,11 +34,12 @@ class UpnpDiscovery; class PluginTimerManager; class NetworkAccessManager; class UpnpDeviceDescriptor; -class QtAvahiServiceBrowser; +class ZeroConfServiceBrowser; class BluetoothLowEnergyManager; namespace nymeaserver { +class Platform; class MqttBroker; class HardwareManagerImplementation : public HardwareManager @@ -46,26 +47,27 @@ class HardwareManagerImplementation : public HardwareManager Q_OBJECT public: - explicit HardwareManagerImplementation(MqttBroker *mqttBroker, QObject *parent = nullptr); + explicit HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, QObject *parent = nullptr); ~HardwareManagerImplementation() override; Radio433 *radio433() override; PluginTimerManager *pluginTimerManager() override; NetworkAccessManager *networkManager() override; UpnpDiscovery *upnpDiscovery() override; - QtAvahiServiceBrowser *avahiBrowser() override; + ZeroConfServiceBrowser *zeroConfServiceBrowser() override; BluetoothLowEnergyManager *bluetoothLowEnergyManager() override; MqttProvider *mqttProvider() override; private: QNetworkAccessManager *m_networkAccessManager = nullptr; + Platform *m_platform = nullptr; + // Hardware Resources PluginTimerManager *m_pluginTimerManager = nullptr; Radio433 *m_radio433 = nullptr; NetworkAccessManager *m_networkManager = nullptr; UpnpDiscovery *m_upnpDiscovery = nullptr; - QtAvahiServiceBrowser *m_avahiBrowser = nullptr; BluetoothLowEnergyManager *m_bluetoothLowEnergyManager = nullptr; MqttProvider *m_mqttProvider = nullptr; }; diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index b66bc2c6..c01ec338 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -5,7 +5,7 @@ include(../nymea.pri) QT += sql INCLUDEPATH += $$top_srcdir/libnymea -LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto -lavahi-common -lavahi-client -lnymea-mqtt +LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto -lnymea-mqtt target.path = $$[QT_INSTALL_LIBS] INSTALLS += target @@ -86,12 +86,6 @@ HEADERS += nymeacore.h \ hardware/network/upnp/upnpdiscoveryimplementation.h \ hardware/network/upnp/upnpdiscoveryrequest.h \ hardware/network/upnp/upnpdiscoveryreplyimplementation.h \ - hardware/network/avahi/qt-watch.h \ - hardware/network/avahi/qtavahiclient.h \ - hardware/network/avahi/qtavahiservice.h \ - hardware/network/avahi/qtavahiservice_p.h \ - hardware/network/avahi/qtavahiservicebrowserimplementation.h \ - hardware/network/avahi/qtavahiservicebrowserimplementation_p.h \ hardware/network/mqtt/mqttproviderimplementation.h \ hardware/network/mqtt/mqttchannelimplementation.h \ debugserverhandler.h \ @@ -172,12 +166,6 @@ SOURCES += nymeacore.cpp \ hardware/network/upnp/upnpdiscoveryimplementation.cpp \ hardware/network/upnp/upnpdiscoveryrequest.cpp \ hardware/network/upnp/upnpdiscoveryreplyimplementation.cpp \ - hardware/network/avahi/qt-watch.cpp \ - hardware/network/avahi/qtavahiclient.cpp \ - hardware/network/avahi/qtavahiservice.cpp \ - hardware/network/avahi/qtavahiservice_p.cpp \ - hardware/network/avahi/qtavahiservicebrowserimplementation.cpp \ - hardware/network/avahi/qtavahiservicebrowserimplementation_p.cpp \ hardware/network/mqtt/mqttproviderimplementation.cpp \ hardware/network/mqtt/mqttchannelimplementation.cpp \ debugserverhandler.cpp \ diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index e7d8ee2f..1968a8b1 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -161,10 +161,10 @@ void NymeaCore::init() { m_userManager = new UserManager(NymeaSettings::settingsPath() + "/user-db.sqlite", this); qCDebug(dcApplication) << "Creating Server Manager"; - m_serverManager = new ServerManager(m_configuration, this); + m_serverManager = new ServerManager(m_platform, m_configuration, this); qCDebug(dcApplication) << "Creating Hardware Manager"; - m_hardwareManager = new HardwareManagerImplementation(m_serverManager->mqttBroker(), this); + m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), this); qCDebug(dcApplication) << "Creating Device Manager (locale:" << m_configuration->locale() << ")"; m_deviceManager = new DeviceManager(m_hardwareManager, m_configuration->locale(), this); diff --git a/libnymea-core/platform/platform.cpp b/libnymea-core/platform/platform.cpp index 4a5c8b05..d149c9b4 100644 --- a/libnymea-core/platform/platform.cpp +++ b/libnymea-core/platform/platform.cpp @@ -23,6 +23,7 @@ #include "platform.h" #include "platform/platformsystemcontroller.h" #include "platform/platformupdatecontroller.h" +#include "platform/platformzeroconfcontroller.h" #include "loggingcategories.h" @@ -44,27 +45,35 @@ Platform::Platform(QObject *parent) : QObject(parent) loadSystemPlugin(path + "/" + entry); } else if (entry.startsWith("libnymea_updateplugin") && entry.endsWith(".so")) { loadUpdatePlugin(path + "/" + entry); + } else if (entry.startsWith("libnymea_zeroconfplugin") && entry.endsWith(".so")) { + loadZeroConfPlugin(path + "/" + entry); } } else if (fi.isDir()) { if (QFileInfo::exists(path + "/" + entry + "/libnymea_systemplugin" + entry + ".so")) { loadSystemPlugin(path + "/" + entry + "/libnymea_systemplugin" + entry + ".so"); } else if (QFileInfo::exists(path + "/" + entry + "/libnymea_updateplugin" + entry + ".so")) { loadUpdatePlugin(path + "/" + entry + "/libnymea_updateplugin" + entry + ".so"); + } else if (QFileInfo::exists(path + "/" + entry + "/libnymea_zeroconfplugin" + entry + ".so")) { + loadZeroConfPlugin(path + "/" + entry + "/libnymea_zeroconfplugin" + entry + ".so"); } } } - if (m_platformSystemController && m_platformUpdateController) { + if (m_platformSystemController && m_platformUpdateController && m_platformZeroConfController) { break; } } if (!m_platformSystemController) { - qCWarning(dcPlatform()) << "Could not load a system plugin. System control features won't be available."; + qCWarning(dcPlatform()) << "No system plugin loaded. System control features won't be available."; m_platformSystemController = new PlatformSystemController(this); } if (!m_platformUpdateController) { - qCWarning(dcPlatform()) << "Could not load an update plugin. System update features won't be available."; + qCWarning(dcPlatform()) << "No update plugin loaded. System update features won't be available."; m_platformUpdateController = new PlatformUpdateController(this); } + if (!m_platformZeroConfController) { + qCWarning(dcPlatform()) << "No ZeroConf plugin loaded. ZeroConf will not be available."; + m_platformZeroConfController = new PlatformZeroConfController(this); + } } PlatformSystemController *Platform::systemController() const @@ -77,6 +86,11 @@ PlatformUpdateController *Platform::updateController() const return m_platformUpdateController; } +PlatformZeroConfController *Platform::zeroConfController() const +{ + return m_platformZeroConfController; +} + QStringList Platform::pluginSearchDirs() const { QStringList searchDirs; @@ -103,16 +117,16 @@ void Platform::loadSystemPlugin(const QString &file) loader.setFileName(file); loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); if (!loader.load()) { - qCWarning(dcPlatform) << "Could not load plugin data of" << file << "\n" << loader.errorString(); + qCWarning(dcPlatform) << loader.errorString(); return; } m_platformSystemController = qobject_cast(loader.instance()); if (!m_platformSystemController) { - qCWarning(dcPlatform) << "Could not get plugin instance of" << file; + qCWarning(dcPlatform) << "Could not get plugin instance of" << loader.fileName(); loader.unload(); return; } - qCDebug(dcPlatform()) << "Loaded system plugin:" << file; + qCDebug(dcPlatform()) << "Loaded system plugin:" << loader.fileName(); m_platformSystemController->setParent(this); } @@ -125,17 +139,39 @@ void Platform::loadUpdatePlugin(const QString &file) loader.setFileName(file); loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); if (!loader.load()) { - qCWarning(dcPlatform) << "Could not load plugin data of" << file << "\n" << loader.errorString(); + qCWarning(dcPlatform) << loader.errorString(); return; } m_platformUpdateController = qobject_cast(loader.instance()); if (!m_platformUpdateController) { - qCWarning(dcPlatform) << "Could not get plugin instance of" << file; + qCWarning(dcPlatform) << "Could not get plugin instance of" << loader.fileName(); loader.unload(); return; } - qCDebug(dcPlatform()) << "Loaded update plugin:" << file; + qCDebug(dcPlatform()) << "Loaded update plugin:" << loader.fileName(); m_platformUpdateController->setParent(this); } +void Platform::loadZeroConfPlugin(const QString &file) +{ + if (m_platformZeroConfController) { + return; // Not loading another... + } + QPluginLoader loader; + loader.setFileName(file); + loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); + if (!loader.load()) { + qCWarning(dcPlatform) << loader.errorString(); + return; + } + m_platformZeroConfController = qobject_cast(loader.instance()); + if (!m_platformZeroConfController) { + qCWarning(dcPlatform) << "Could not get plugin instance of" << loader.fileName(); + loader.unload(); + return; + } + qCDebug(dcPlatform()) << "Loaded ZeroConf plugin:" << loader.fileName(); + m_platformZeroConfController->setParent(this); +} + } diff --git a/libnymea-core/platform/platform.h b/libnymea-core/platform/platform.h index 2b8657b7..b60f78b2 100644 --- a/libnymea-core/platform/platform.h +++ b/libnymea-core/platform/platform.h @@ -27,6 +27,7 @@ class PlatformSystemController; class PlatformUpdateController; +class PlatformZeroConfController; namespace nymeaserver { @@ -38,16 +39,19 @@ public: PlatformSystemController *systemController() const; PlatformUpdateController *updateController() const; + PlatformZeroConfController *zeroConfController() const; private: QStringList pluginSearchDirs() const; void loadSystemPlugin(const QString &file); void loadUpdatePlugin(const QString &file); + void loadZeroConfPlugin(const QString &file); private: PlatformSystemController *m_platformSystemController = nullptr; PlatformUpdateController *m_platformUpdateController = nullptr; + PlatformZeroConfController *m_platformZeroConfController = nullptr; }; } diff --git a/libnymea-core/servermanager.cpp b/libnymea-core/servermanager.cpp index 6daa1e43..10ccaa9d 100644 --- a/libnymea-core/servermanager.cpp +++ b/libnymea-core/servermanager.cpp @@ -37,6 +37,8 @@ #include "nymeacore.h" #include "certificategenerator.h" #include "nymeasettings.h" +#include "platform/platform.h" +#include "platform/platformzeroconfcontroller.h" #include "jsonrpc/jsonrpcserver.h" #include "servers/mocktcpserver.h" @@ -47,6 +49,8 @@ #include "servers/bluetoothserver.h" #include "servers/mqttbroker.h" +#include "network/zeroconf/zeroconfservicepublisher.h" + #include #include #include @@ -54,8 +58,9 @@ namespace nymeaserver { /*! Constructs a \l{ServerManager} with the given \a configuration and \a parent. */ -ServerManager::ServerManager(NymeaConfiguration *configuration, QObject *parent) : +ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configuration, QObject *parent) : QObject(parent), + m_platform(platform), m_sslConfiguration(QSslConfiguration()) { if (!QSslSocket::supportsSsl()) { @@ -108,14 +113,18 @@ ServerManager::ServerManager(NymeaConfiguration *configuration, QObject *parent) TcpServer *tcpServer = new TcpServer(config, m_sslConfiguration, this); m_jsonServer->registerTransportInterface(tcpServer, config.authenticationEnabled); m_tcpServers.insert(config.id, tcpServer); - tcpServer->startServer(); + if (tcpServer->startServer()) { + registerZeroConfService(config, "nymea-tcp", "_jsonrpc._tcp"); + } } foreach (const ServerConfiguration &config, configuration->webSocketServerConfigurations()) { WebSocketServer *webSocketServer = new WebSocketServer(config, m_sslConfiguration, this); m_jsonServer->registerTransportInterface(webSocketServer, config.authenticationEnabled); m_webSocketServers.insert(config.id, webSocketServer); - webSocketServer->startServer(); + if (webSocketServer->startServer()) { + registerZeroConfService(config, "nymea-ws", "_ws._tcp"); + } } m_bluetoothServer = new BluetoothServer(this); @@ -128,11 +137,16 @@ ServerManager::ServerManager(NymeaConfiguration *configuration, QObject *parent) WebServer *webServer = new WebServer(config, m_sslConfiguration, this); m_restServer->registerWebserver(webServer); m_webServers.insert(config.id, webServer); + if (webServer->startServer()) { + registerZeroConfService(config, "nymea-http", "_http._tcp"); + } } m_mqttBroker = new MqttBroker(this); foreach (const ServerConfiguration &config, configuration->mqttServerConfigurations()) { - m_mqttBroker->startServer(config); + if (m_mqttBroker->startServer(config)) { + registerZeroConfService(config, "nymea-mqtt", "_mqtt._tcp"); + } } m_mqttBroker->updatePolicies(configuration->mqttPolicies().values()); @@ -183,6 +197,7 @@ void ServerManager::tcpServerConfigurationChanged(const QString &id) TcpServer *server = m_tcpServers.value(id); if (server) { qDebug(dcServerManager()) << "Restarting TCP server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); + unregisterZeroConfService(config.id); server->stopServer(); server->setConfiguration(config); } else { @@ -191,7 +206,9 @@ void ServerManager::tcpServerConfigurationChanged(const QString &id) m_tcpServers.insert(config.id, server); } m_jsonServer->registerTransportInterface(server, config.authenticationEnabled); - server->startServer(); + if (server->startServer()) { + registerZeroConfService(config, "nymea-tcp", "_jsonrpc._tcp"); + } } void ServerManager::tcpServerConfigurationRemoved(const QString &id) @@ -202,6 +219,7 @@ void ServerManager::tcpServerConfigurationRemoved(const QString &id) } TcpServer *server = m_tcpServers.take(id); m_jsonServer->unregisterTransportInterface(server); + unregisterZeroConfService(id); server->stopServer(); server->deleteLater(); } @@ -212,6 +230,7 @@ void ServerManager::webSocketServerConfigurationChanged(const QString &id) ServerConfiguration config = NymeaCore::instance()->configuration()->webSocketServerConfigurations().value(id); if (server) { qDebug(dcServerManager()) << "Restarting WebSocket server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); + unregisterZeroConfService(id); server->stopServer(); server->setConfiguration(config); } else { @@ -220,7 +239,9 @@ void ServerManager::webSocketServerConfigurationChanged(const QString &id) m_webSocketServers.insert(server->configuration().id, server); } m_jsonServer->registerTransportInterface(server, config.authenticationEnabled); - server->startServer(); + if (server->startServer()) { + registerZeroConfService(config, "nymea-ws", "_ws._tcp"); + } } void ServerManager::webSocketServerConfigurationRemoved(const QString &id) @@ -231,6 +252,7 @@ void ServerManager::webSocketServerConfigurationRemoved(const QString &id) } WebSocketServer *server = m_webSocketServers.take(id); m_jsonServer->unregisterTransportInterface(server); + unregisterZeroConfService(id); server->stopServer(); server->deleteLater(); } @@ -241,6 +263,7 @@ void ServerManager::webServerConfigurationChanged(const QString &id) WebServer *server = m_webServers.value(id); if (server) { qDebug(dcServerManager()) << "Restarting Web server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); + unregisterZeroConfService(id); server->stopServer(); server->reconfigureServer(config); } else { @@ -249,6 +272,9 @@ void ServerManager::webServerConfigurationChanged(const QString &id) m_restServer->registerWebserver(server); m_webServers.insert(config.id, server); } + if (server->startServer()) { + registerZeroConfService(config, "nymea-http", "_http._tcp"); + } } void ServerManager::webServerConfigurationRemoved(const QString &id) @@ -258,6 +284,7 @@ void ServerManager::webServerConfigurationRemoved(const QString &id) return; } WebServer *server = m_webServers.take(id); + unregisterZeroConfService(id); server->stopServer(); server->deleteLater(); } @@ -266,13 +293,18 @@ void ServerManager::mqttServerConfigurationChanged(const QString &id) { ServerConfiguration config = NymeaCore::instance()->configuration()->mqttServerConfigurations().value(id); if (m_mqttBroker->isRunning(id)) { + unregisterZeroConfService(id); m_mqttBroker->stopServer(id); } - m_mqttBroker->startServer(config, m_sslConfiguration); + if (m_mqttBroker->startServer(config, m_sslConfiguration)) { + registerZeroConfService(config, "nymea-mqtt", "_mqtt._tcp"); + } + } void ServerManager::mqttServerConfigurationRemoved(const QString &id) { + unregisterZeroConfService(id); m_mqttBroker->stopServer(id); } @@ -286,6 +318,29 @@ void ServerManager::mqttPolicyRemoved(const QString &clientId) m_mqttBroker->removePolicy(clientId); } +bool ServerManager::registerZeroConfService(const ServerConfiguration &configuration, const QString &namePrefix, const QString &serviceType) +{ + // Note: reversed order + QHash txt; + txt.insert("jsonrpcVersion", JSON_PROTOCOL_VERSION); + txt.insert("serverVersion", NYMEA_VERSION_STRING); + txt.insert("manufacturer", "guh GmbH"); + txt.insert("uuid", NymeaCore::instance()->configuration()->serverUuid().toString()); + txt.insert("name", NymeaCore::instance()->configuration()->serverName()); + txt.insert("sslEnabled", configuration.sslEnabled ? "true" : "false"); + QString name = namePrefix + "-" + configuration.id; + if (!m_platform->zeroConfController()->zeroConfServicePublisher()->registerService(configuration.id, name, configuration.address, static_cast(configuration.port), serviceType, txt)) { + qCWarning(dcTcpServer()) << "Could not register ZeroConf service for" << configuration; + return false; + } + return true; +} + +void ServerManager::unregisterZeroConfService(const QString &configId) +{ + m_platform->zeroConfController()->zeroConfServicePublisher()->unregisterService(configId); +} + bool ServerManager::loadCertificate(const QString &certificateKeyFileName, const QString &certificateFileName) { QFile certificateKeyFile(certificateKeyFileName); diff --git a/libnymea-core/servermanager.h b/libnymea-core/servermanager.h index 10f3df35..6c78ed02 100644 --- a/libnymea-core/servermanager.h +++ b/libnymea-core/servermanager.h @@ -33,6 +33,7 @@ class MockTcpServer; namespace nymeaserver { +class Platform; class NymeaConfiguration; class JsonRPCServer; class TcpServer; @@ -46,7 +47,7 @@ class ServerManager : public QObject { Q_OBJECT public: - explicit ServerManager(NymeaConfiguration *configuration, QObject *parent = nullptr); + explicit ServerManager(Platform *platform, NymeaConfiguration *configuration, QObject *parent = nullptr); // Interfaces JsonRPCServer *jsonServer() const; @@ -71,6 +72,12 @@ private slots: void mqttPolicyRemoved(const QString &clientId); private: + bool registerZeroConfService(const ServerConfiguration &configuration, const QString &namePrefix, const QString &serviceType); + void unregisterZeroConfService(const QString &configId); + +private: + Platform *m_platform = nullptr; + // Interfaces JsonRPCServer *m_jsonServer; RestServer *m_restServer; diff --git a/libnymea-core/servers/rest/restserver.cpp b/libnymea-core/servers/rest/restserver.cpp index e852ee4b..24609646 100644 --- a/libnymea-core/servers/rest/restserver.cpp +++ b/libnymea-core/servers/rest/restserver.cpp @@ -63,7 +63,6 @@ void RestServer::registerWebserver(WebServer *webServer) connect(webServer, &WebServer::clientConnected, this, &RestServer::clientConnected); connect(webServer, &WebServer::clientDisconnected, this, &RestServer::clientDisconnected); connect(webServer, &WebServer::httpRequestReady, this, &RestServer::processHttpRequest); - QMetaObject::invokeMethod(webServer, "startServer", Qt::QueuedConnection); } void RestServer::setup() diff --git a/libnymea-core/servers/tcpserver.cpp b/libnymea-core/servers/tcpserver.cpp index d3f810c4..4c42d672 100644 --- a/libnymea-core/servers/tcpserver.cpp +++ b/libnymea-core/servers/tcpserver.cpp @@ -80,8 +80,6 @@ TcpServer::TcpServer(const ServerConfiguration &configuration, const QSslConfigu m_server(nullptr), m_sslConfig(sslConfiguration) { - m_avahiService = new QtAvahiService(this); - connect(m_avahiService, &QtAvahiService::serviceStateChanged, this, &TcpServer::onAvahiServiceStateChanged); } /*! Destructor of this \l{TcpServer}. */ @@ -155,29 +153,6 @@ void TcpServer::onDataAvailable(QSslSocket * socket, const QByteArray &data) emit dataAvailable(clientId, data); } -void TcpServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state) -{ - Q_UNUSED(state) -} - -void TcpServer::resetAvahiService() -{ - if (m_avahiService) - m_avahiService->resetService(); - - // Note: reversed order - QHash txt; - txt.insert("jsonrpcVersion", JSON_PROTOCOL_VERSION); - txt.insert("serverVersion", NYMEA_VERSION_STRING); - txt.insert("manufacturer", "guh GmbH"); - txt.insert("uuid", NymeaCore::instance()->configuration()->serverUuid().toString()); - txt.insert("name", NymeaCore::instance()->configuration()->serverName()); - txt.insert("sslEnabled", configuration().sslEnabled ? "true" : "false"); - if (!m_avahiService->registerService(QString("nymea-tcp-%1").arg(configuration().id), configuration().address, static_cast(configuration().port), "_jsonrpc._tcp", txt)) { - qCWarning(dcTcpServer()) << "Could not register avahi service for" << configuration(); - } -} - /*! Returns true if this \l{TcpServer} could be reconfigured with the given \a config. */ void TcpServer::reconfigureServer(const ServerConfiguration &config) @@ -198,7 +173,6 @@ void TcpServer::reconfigureServer(const ServerConfiguration &config) void TcpServer::setServerName(const QString &serverName) { m_serverName = serverName; - resetAvahiService(); } /*! Returns true if this \l{TcpServer} started successfully. @@ -220,7 +194,6 @@ bool TcpServer::startServer() connect(m_server, &SslServer::dataAvailable, this, &TcpServer::onDataAvailable); qCDebug(dcTcpServer()) << "Started Tcp server" << serverUrl().toString(); - resetAvahiService(); return true; } @@ -231,9 +204,6 @@ bool TcpServer::startServer() */ bool TcpServer::stopServer() { - if (m_avahiService) - m_avahiService->resetService(); - if (!m_server) return true; diff --git a/libnymea-core/servers/tcpserver.h b/libnymea-core/servers/tcpserver.h index f229af4a..29f923c7 100644 --- a/libnymea-core/servers/tcpserver.h +++ b/libnymea-core/servers/tcpserver.h @@ -32,7 +32,6 @@ #include #include "transportinterface.h" -#include "hardware/network/avahi/qtavahiservice.h" #include "loggingcategories.h" @@ -84,8 +83,6 @@ public: private: QTimer *m_timer; - QtAvahiService *m_avahiService; - SslServer * m_server; QHash m_clientList; @@ -97,9 +94,6 @@ private slots: void onDataAvailable(QSslSocket *socket, const QByteArray &data); void onError(QAbstractSocket::SocketError error); - void onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state); - void resetAvahiService(); - public slots: void reconfigureServer(const ServerConfiguration &configuration); void setServerName(const QString &serverName) override; diff --git a/libnymea-core/servers/webserver.cpp b/libnymea-core/servers/webserver.cpp index 3f399092..8b987859 100644 --- a/libnymea-core/servers/webserver.cpp +++ b/libnymea-core/servers/webserver.cpp @@ -106,9 +106,6 @@ WebServer::WebServer(const WebServerConfiguration &configuration, const QSslConf m_configuration.publicFolder = QCoreApplication::applicationDirPath(); } qCDebug(dcWebServer()) << "Starting WebServer. Interface:" << m_configuration.address << "Port:" << m_configuration.port << "SSL:" << m_configuration.sslEnabled << "AUTH:" << m_configuration.authenticationEnabled << "Public folder:" << QDir(m_configuration.publicFolder).canonicalPath(); - - m_avahiService = new QtAvahiService(this); - connect(m_avahiService, &QtAvahiService::serviceStateChanged, this, &WebServer::onAvahiServiceStateChanged); } /*! Destructor of this \l{WebServer}. */ @@ -553,32 +550,6 @@ void WebServer::onAsyncReplyFinished() reply->deleteLater(); } -void WebServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state) -{ - Q_UNUSED(state) -} - -void WebServer::resetAvahiService() -{ - if (!m_avahiService) - return; - - m_avahiService->resetService(); - - // Note: reversed order - QHash txt; - txt.insert("jsonrpcVersion", JSON_PROTOCOL_VERSION); - txt.insert("serverVersion", NYMEA_VERSION_STRING); - txt.insert("manufacturer", "guh GmbH"); - txt.insert("uuid", NymeaCore::instance()->configuration()->serverUuid().toString()); - txt.insert("name", NymeaCore::instance()->configuration()->serverName()); - txt.insert("sslEnabled", m_configuration.sslEnabled ? "true" : "false"); - - if (!m_avahiService->registerService(QString("nymea-http-%1").arg(m_configuration.id), m_configuration.address, static_cast(m_configuration.port), "_http._tcp", txt)) { - qCWarning(dcTcpServer()) << "Could not register avahi service for" << m_configuration; - } -} - /*! Set the configuration of this \l{WebServer} to the given \a config. * * \sa WebServerConfiguration @@ -602,7 +573,6 @@ void WebServer::reconfigureServer(const WebServerConfiguration &config) void WebServer::setServerName(const QString &serverName) { m_serverName = serverName; - resetAvahiService(); } /*! Returns true if this \l{WebServer} started successfully. */ @@ -615,7 +585,6 @@ bool WebServer::startServer() } qCDebug(dcWebServer()) << "Started web server on" << serverUrl().toString(); - resetAvahiService(); m_enabled = true; return true; @@ -624,9 +593,6 @@ bool WebServer::startServer() /*! Returns true if this \l{WebServer} stopped successfully. */ bool WebServer::stopServer() { - if (m_avahiService) - m_avahiService->resetService(); - foreach (QSslSocket *client, m_clientList.values()) client->close(); diff --git a/libnymea-core/servers/webserver.h b/libnymea-core/servers/webserver.h index 1d9a31e8..0a63d27b 100644 --- a/libnymea-core/servers/webserver.h +++ b/libnymea-core/servers/webserver.h @@ -36,8 +36,6 @@ #include "nymeaconfiguration.h" -#include "hardware/network/avahi/qtavahiservice.h" - // Note: Hypertext Transfer Protocol (HTTP/1.1) from the Internet Engineering Task Force (IETF): // https://tools.ietf.org/html/rfc7231 @@ -86,7 +84,6 @@ private: QList m_webServerClients; QHash m_incompleteRequests; - QtAvahiService *m_avahiService = nullptr; QString m_serverName; WebServerConfiguration m_configuration; QSslConfiguration m_sslConfiguration; @@ -115,9 +112,6 @@ private slots: void onError(QAbstractSocket::SocketError error); void onAsyncReplyFinished(); - void onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state); - void resetAvahiService(); - public slots: void reconfigureServer(const WebServerConfiguration &config); void setServerName(const QString &serverName); diff --git a/libnymea-core/servers/websocketserver.cpp b/libnymea-core/servers/websocketserver.cpp index 24dfbc2a..72d42b64 100644 --- a/libnymea-core/servers/websocketserver.cpp +++ b/libnymea-core/servers/websocketserver.cpp @@ -65,8 +65,6 @@ WebSocketServer::WebSocketServer(const ServerConfiguration &configuration, const m_sslConfiguration(sslConfiguration), m_enabled(false) { - m_avahiService = new QtAvahiService(this); - connect(m_avahiService, &QtAvahiService::serviceStateChanged, this, &WebSocketServer::onAvahiServiceStateChanged); } /*! Destructor of this \l{WebSocketServer}. */ @@ -117,19 +115,6 @@ void WebSocketServer::terminateClientConnection(const QUuid &clientId) } } -QHash WebSocketServer::createTxtRecord() -{ - // Note: reversed order - QHash txt; - txt.insert("jsonrpcVersion", JSON_PROTOCOL_VERSION); - txt.insert("serverVersion", NYMEA_VERSION_STRING); - txt.insert("manufacturer", "guh GmbH"); - txt.insert("uuid", NymeaCore::instance()->configuration()->serverUuid().toString()); - txt.insert("name", NymeaCore::instance()->configuration()->serverName()); - txt.insert("sslEnabled", configuration().sslEnabled ? "true" : "false"); - return txt; -} - void WebSocketServer::onClientConnected() { // got a new client connected @@ -202,21 +187,6 @@ void WebSocketServer::onPing(quint64 elapsedTime, const QByteArray &payload) qCDebug(dcWebSocketServer) << "Ping response from" << clientId.toString() << elapsedTime << payload; } -void WebSocketServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state) -{ - Q_UNUSED(state) -} - -void WebSocketServer::resetAvahiService() -{ - if (!m_avahiService) - return; - - m_avahiService->resetService(); - if (!m_avahiService->registerService(QString("nymea-ws-%1").arg(configuration().id), configuration().address, static_cast(configuration().port), "_ws._tcp", createTxtRecord())) { - qCWarning(dcWebSocketServer()) << "Could not register avahi service for" << configuration(); - } -} /*! Returns true if this \l{WebSocketServer} could be reconfigured with the given \a config. */ void WebSocketServer::reconfigureServer(const ServerConfiguration &config) @@ -240,7 +210,6 @@ void WebSocketServer::reconfigureServer(const ServerConfiguration &config) void WebSocketServer::setServerName(const QString &serverName) { m_serverName = serverName; - resetAvahiService(); } /*! Returns true if this \l{WebSocketServer} started successfully. @@ -264,7 +233,6 @@ bool WebSocketServer::startServer() } qCDebug(dcWebSocketServer()) << "Server started on" << serverUrl().toString(); - resetAvahiService(); return true; } @@ -274,9 +242,6 @@ bool WebSocketServer::startServer() */ bool WebSocketServer::stopServer() { - if (m_avahiService) - m_avahiService->resetService(); - foreach (QWebSocket *client, m_clientList.values()) { client->close(QWebSocketProtocol::CloseCodeNormal, "Stop server"); } diff --git a/libnymea-core/servers/websocketserver.h b/libnymea-core/servers/websocketserver.h index c6d82525..1210a04f 100644 --- a/libnymea-core/servers/websocketserver.h +++ b/libnymea-core/servers/websocketserver.h @@ -28,7 +28,6 @@ #include #include -#include "hardware/network/avahi/qtavahiservice.h" #include "transportinterface.h" // Note: WebSocket Protocol from the Internet Engineering Task Force (IETF) -> RFC6455 V13: @@ -55,12 +54,9 @@ public: private: QWebSocketServer *m_server = nullptr; QHash m_clientList; - QtAvahiService *m_avahiService = nullptr; QSslConfiguration m_sslConfiguration; bool m_enabled; - QHash createTxtRecord(); - private slots: void onClientConnected(); void onClientDisconnected(); @@ -70,9 +66,6 @@ private slots: void onServerError(QAbstractSocket::SocketError error); void onPing(quint64 elapsedTime, const QByteArray & payload); - void onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state); - void resetAvahiService(); - public slots: void reconfigureServer(const ServerConfiguration &config); void setServerName(const QString &serverName) override; diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h index 63cb2493..45f9893d 100644 --- a/libnymea/hardwaremanager.h +++ b/libnymea/hardwaremanager.h @@ -30,7 +30,7 @@ class UpnpDiscovery; class PluginTimerManager; class NetworkAccessManager; class UpnpDeviceDescriptor; -class QtAvahiServiceBrowser; +class ZeroConfServiceBrowser; class BluetoothLowEnergyManager; class MqttProvider; class HardwareResource; @@ -47,7 +47,7 @@ public: virtual PluginTimerManager *pluginTimerManager() = 0; virtual NetworkAccessManager *networkManager() = 0; virtual UpnpDiscovery *upnpDiscovery() = 0; - virtual QtAvahiServiceBrowser *avahiBrowser() = 0; + virtual ZeroConfServiceBrowser *zeroConfServiceBrowser() = 0; virtual BluetoothLowEnergyManager *bluetoothLowEnergyManager() = 0; virtual MqttProvider *mqttProvider() = 0; diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index 56e6a37e..9d440557 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -8,8 +8,6 @@ DEFINES += LIBNYMEA_LIBRARY QMAKE_LFLAGS += -fPIC -LIBS += -lavahi-common -lavahi-client - HEADERS += devicemanager.h \ libnymea.h \ platform/package.h \ @@ -31,8 +29,9 @@ HEADERS += devicemanager.h \ network/upnp/upnpdiscoveryreply.h \ network/networkaccessmanager.h \ network/oauth2.h \ - network/avahi/qtavahiservicebrowser.h \ - network/avahi/avahiserviceentry.h \ + network/zeroconf/zeroconfservicebrowser.h \ + network/zeroconf/zeroconfserviceentry.h \ + network/zeroconf/zeroconfservicepublisher.h \ hardware/bluetoothlowenergy/bluetoothlowenergydevice.h \ hardware/bluetoothlowenergy/bluetoothdiscoveryreply.h \ hardware/bluetoothlowenergy/bluetoothlowenergymanager.h \ @@ -69,7 +68,8 @@ HEADERS += devicemanager.h \ network/mqtt/mqttchannel.h \ translator.h \ platform/platformsystemcontroller.h \ - platform/platformupdatecontroller.h + platform/platformupdatecontroller.h \ + platform/platformzeroconfcontroller.h \ SOURCES += devicemanager.cpp \ loggingcategories.cpp \ @@ -90,8 +90,9 @@ SOURCES += devicemanager.cpp \ network/upnp/upnpdiscoveryreply.cpp \ network/networkaccessmanager.cpp \ network/oauth2.cpp \ - network/avahi/avahiserviceentry.cpp \ - network/avahi/qtavahiservicebrowser.cpp \ + network/zeroconf/zeroconfserviceentry.cpp \ + network/zeroconf/zeroconfservicebrowser.cpp \ + network/zeroconf/zeroconfservicepublisher.cpp \ hardware/bluetoothlowenergy/bluetoothlowenergymanager.cpp \ hardware/bluetoothlowenergy/bluetoothlowenergydevice.cpp \ hardware/bluetoothlowenergy/bluetoothdiscoveryreply.cpp \ @@ -128,7 +129,8 @@ SOURCES += devicemanager.cpp \ network/mqtt/mqttchannel.cpp \ translator.cpp \ platform/platformsystemcontroller.cpp \ - platform/platformupdatecontroller.cpp + platform/platformupdatecontroller.cpp \ + platform/platformzeroconfcontroller.cpp \ RESOURCES += \ diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index 657174a2..4496ef6c 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -27,6 +27,7 @@ Q_LOGGING_CATEGORY(dcDeviceManager, "DeviceManager") Q_LOGGING_CATEGORY(dcSystem, "System") Q_LOGGING_CATEGORY(dcPlatform, "Platform") Q_LOGGING_CATEGORY(dcPlatformUpdate, "PlatformUpdate") +Q_LOGGING_CATEGORY(dcPlatformZeroConf, "PlatformZeroConf") Q_LOGGING_CATEGORY(dcTimeManager, "TimeManager") Q_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine") Q_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug") @@ -44,8 +45,6 @@ Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc") Q_LOGGING_CATEGORY(dcJsonRpcTraffic, "JsonRpcTraffic") Q_LOGGING_CATEGORY(dcRest, "Rest") Q_LOGGING_CATEGORY(dcOAuth2, "OAuth2") -Q_LOGGING_CATEGORY(dcAvahi, "Avahi") -Q_LOGGING_CATEGORY(dcAvahiDebug, "AvahiDebug") Q_LOGGING_CATEGORY(dcUpnp, "UPnP") Q_LOGGING_CATEGORY(dcBluetooth, "Bluetooth") Q_LOGGING_CATEGORY(dcCloud, "Cloud") diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h index d9c8ef42..12d303f5 100644 --- a/libnymea/loggingcategories.h +++ b/libnymea/loggingcategories.h @@ -32,6 +32,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcDeviceManager) Q_DECLARE_LOGGING_CATEGORY(dcSystem) Q_DECLARE_LOGGING_CATEGORY(dcPlatform) Q_DECLARE_LOGGING_CATEGORY(dcPlatformUpdate) +Q_DECLARE_LOGGING_CATEGORY(dcPlatformZeroConf) Q_DECLARE_LOGGING_CATEGORY(dcTimeManager) Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine) Q_DECLARE_LOGGING_CATEGORY(dcRuleEngineDebug) @@ -49,8 +50,6 @@ Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc) Q_DECLARE_LOGGING_CATEGORY(dcJsonRpcTraffic) Q_DECLARE_LOGGING_CATEGORY(dcRest) Q_DECLARE_LOGGING_CATEGORY(dcOAuth2) -Q_DECLARE_LOGGING_CATEGORY(dcAvahi) -Q_DECLARE_LOGGING_CATEGORY(dcAvahiDebug) Q_DECLARE_LOGGING_CATEGORY(dcUpnp) Q_DECLARE_LOGGING_CATEGORY(dcBluetooth) Q_DECLARE_LOGGING_CATEGORY(dcCloud) diff --git a/libnymea/network/avahi/qtavahiservicebrowser.cpp b/libnymea/network/zeroconf/zeroconfservicebrowser.cpp similarity index 60% rename from libnymea/network/avahi/qtavahiservicebrowser.cpp rename to libnymea/network/zeroconf/zeroconfservicebrowser.cpp index ad20d68f..a09951a6 100644 --- a/libnymea/network/avahi/qtavahiservicebrowser.cpp +++ b/libnymea/network/zeroconf/zeroconfservicebrowser.cpp @@ -21,13 +21,13 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! - \class QtAvahiServiceBrowser + \class ZeroConfServiceBrowser \brief Allows to browse avahi services in the local network. \ingroup hardware \inmodule libnymea - The QtAvahiServiceBrowser allows to discover the avahi network and get services. + The ZeroConfServiceBrowser allows to discover the avahi network and get services. \chapter Example @@ -37,7 +37,7 @@ \tt devicepluginexample.h \code - #include "network/avahi/avahiserviceentry.h" + #include "network/avahi/ZeroConfServiceEntry.h" class DevicePluginExample : public DevicePlugin { @@ -47,8 +47,8 @@ void init() override; private slots: - void onServiceEntryAdded(const AvahiServiceEntry &serviceEntry); - void onServiceEntryRemoved(const AvahiServiceEntry &serviceEntry); + void onServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry); + void onServiceEntryRemoved(const ZeroConfServiceEntry &serviceEntry); ... @@ -60,17 +60,17 @@ \code void DevicePluginExample::init() { - connect(hardwareManager()->avahiBrowser(), &QtAvahiServiceBrowser::serviceEntryAdded, this, &DevicePluginExample::onServiceEntryAdded); - connect(hardwareManager()->avahiBrowser(), &QtAvahiServiceBrowser::serviceEntryRemoved, this, &DevicePluginExample::onServiceEntryRemoved); + connect(hardwareManager()->avahiBrowser(), &ZeroConfServiceBrowser::serviceEntryAdded, this, &DevicePluginExample::onServiceEntryAdded); + connect(hardwareManager()->avahiBrowser(), &ZeroConfServiceBrowser::serviceEntryRemoved, this, &DevicePluginExample::onServiceEntryRemoved); } - void DevicePluginExample::onServiceEntryAdded(const AvahiServiceEntry &serviceEntry) { + void DevicePluginExample::onServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry) { qCDebug(dcExample()) << "New service added to network:" << serviceEntry; ... } - void DevicePluginExample::onServiceEntryRemoved(const AvahiServiceEntry &serviceEntry) { + void DevicePluginExample::onServiceEntryRemoved(const ZeroConfServiceEntry &serviceEntry) { qCDebug(dcExample()) << "Service removed from network:" << serviceEntry; ... @@ -78,34 +78,54 @@ \endcode - \sa AvahiServiceEntry + \sa ZeroConfServiceEntry */ -/*! \fn QtAvahiServiceBrowser::~QtAvahiServiceBrowser(); - Destroys this QtAvahiServiceBrowser; +/*! \fn ZeroConfServiceBrowser::~ZeroConfServiceBrowser(); + Destroys this ZeroConfServiceBrowser; */ -/*! \fn QList QtAvahiServiceBrowser::serviceEntries() const; +/*! \fn QList ZeroConfServiceBrowser::serviceEntries() const; Returns the list of available service entries in the network of this browser. */ // Signals -/*! \fn void QtAvahiServiceBrowser::serviceEntryAdded(const AvahiServiceEntry &entry); +/*! \fn void ZeroConfServiceBrowser::serviceEntryAdded(const ZeroConfServiceEntry &entry); This signal will be emitted when a new \a entry was added to the current entry list. */ -/*! \fn void QtAvahiServiceBrowser::serviceEntryRemoved(const AvahiServiceEntry &entry); +/*! \fn void ZeroConfServiceBrowser::serviceEntryRemoved(const ZeroConfServiceEntry &entry); This signal will be emitted when a new \a entry was removed from the current entry list. */ -#include "qtavahiservicebrowser.h" +#include "zeroconfservicebrowser.h" -/*! Constructs a new \l{QtAvahiServiceBrowser} with the given \a parent. */ -QtAvahiServiceBrowser::QtAvahiServiceBrowser(QObject *parent) : - HardwareResource("Avahi service browser", parent) +/*! Constructs a new \l{ZeroConfServiceBrowser} with the given \a parent. */ +ZeroConfServiceBrowser::ZeroConfServiceBrowser(QObject *parent) : + HardwareResource("ZeroConf service browser", parent) { } +bool ZeroConfServiceBrowser::available() const +{ + return false; +} + +bool ZeroConfServiceBrowser::enabled() const +{ + return false; +} + +void ZeroConfServiceBrowser::setEnabled(bool enabled) +{ + Q_UNUSED(enabled) +} + +QList ZeroConfServiceBrowser::serviceEntries() const +{ + return {}; +} + diff --git a/libnymea/network/avahi/qtavahiservicebrowser.h b/libnymea/network/zeroconf/zeroconfservicebrowser.h similarity index 72% rename from libnymea/network/avahi/qtavahiservicebrowser.h rename to libnymea/network/zeroconf/zeroconfservicebrowser.h index a4f20c85..7c764354 100644 --- a/libnymea/network/avahi/qtavahiservicebrowser.h +++ b/libnymea/network/zeroconf/zeroconfservicebrowser.h @@ -20,30 +20,34 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef QTAVAHISERVICEBROWSER_H -#define QTAVAHISERVICEBROWSER_H +#ifndef ZEROCONFSERVICEBROWSER_H +#define ZEROCONFSERVICEBROWSER_H #include -#include #include "libnymea.h" #include "hardwareresource.h" -#include "avahiserviceentry.h" +#include "zeroconfserviceentry.h" -class LIBNYMEA_EXPORT QtAvahiServiceBrowser : public HardwareResource +class LIBNYMEA_EXPORT ZeroConfServiceBrowser : public HardwareResource { Q_OBJECT public: - explicit QtAvahiServiceBrowser(QObject *parent = nullptr); - virtual ~QtAvahiServiceBrowser() = default; + explicit ZeroConfServiceBrowser(QObject *parent = nullptr); + virtual ~ZeroConfServiceBrowser() = default; - virtual QList serviceEntries() const = 0; + virtual bool available() const override; + virtual bool enabled() const override; + virtual void setEnabled(bool enabled) override; + + + virtual QList serviceEntries() const; signals: - void serviceEntryAdded(const AvahiServiceEntry &entry); - void serviceEntryRemoved(const AvahiServiceEntry &entry); + void serviceEntryAdded(const ZeroConfServiceEntry &entry); + void serviceEntryRemoved(const ZeroConfServiceEntry &entry); }; -#endif // QTAVAHISERVICEBROWSER_H +#endif // ZEROCONFSERVICEBROWSER_H diff --git a/libnymea/network/avahi/avahiserviceentry.cpp b/libnymea/network/zeroconf/zeroconfserviceentry.cpp similarity index 51% rename from libnymea/network/avahi/avahiserviceentry.cpp rename to libnymea/network/zeroconf/zeroconfserviceentry.cpp index a5c55be3..1cc73f03 100644 --- a/libnymea/network/avahi/avahiserviceentry.cpp +++ b/libnymea/network/zeroconf/zeroconfserviceentry.cpp @@ -21,7 +21,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! - \class AvahiServiceEntry + \class ZeroConfServiceEntry \brief Holds information about an avahi service entry. \ingroup types @@ -31,19 +31,18 @@ */ -#include "avahiserviceentry.h" +#include "zeroconfserviceentry.h" -/*! Constructs an empty invalid \l{AvahiServiceEntry}*/ -AvahiServiceEntry::AvahiServiceEntry() : +/*! Constructs an empty invalid \l{ZeroConfServiceEntry}*/ +ZeroConfServiceEntry::ZeroConfServiceEntry() : m_port(0), m_protocol(QAbstractSocket::UnknownNetworkLayerProtocol) { } - -/*! Constructs a new \l{AvahiServiceEntry} with the given \a name, \a serviceType, \a hostAddress, \a domain, \a hostName, \a port, \a protocol, \a txt and \a flags.*/ -AvahiServiceEntry::AvahiServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags) : +/*! Constructs a new \l{ZeroConfServiceEntry} with the given \a name, \a serviceType, \a hostAddress, \a domain, \a hostName, \a port, \a protocol, \a txt and flags.*/ +ZeroConfServiceEntry::ZeroConfServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, bool cached, bool isWideArea, bool isMulticast, bool isLocal, bool isOurOwn): m_name(name), m_serviceType(serviceType), m_hostAddress(hostAddress), @@ -52,103 +51,101 @@ AvahiServiceEntry::AvahiServiceEntry(QString name, QString serviceType, QHostAdd m_port(port), m_protocol(protocol), m_txt(txt), - m_flags(flags) + m_isCached(cached), + m_isWideArea(isWideArea), + m_isMulticast(isMulticast), + m_isLocal(isLocal), + m_isOurOwn(isOurOwn) { } -/*! Returns the name of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::name() const +/*! Returns the name of this \l{ZeroConfServiceEntry}.*/ +QString ZeroConfServiceEntry::name() const { return m_name; } -/*! Returns the service type of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::serviceType() const +/*! Returns the service type of this \l{ZeroConfServiceEntry}.*/ +QString ZeroConfServiceEntry::serviceType() const { return m_serviceType; } -/*! Returns the host address of this \l{AvahiServiceEntry}.*/ -QHostAddress AvahiServiceEntry::hostAddress() const +/*! Returns the host address of this \l{ZeroConfServiceEntry}.*/ +QHostAddress ZeroConfServiceEntry::hostAddress() const { return m_hostAddress; } -/*! Returns the domain of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::domain() const +/*! Returns the domain of this \l{ZeroConfServiceEntry}.*/ +QString ZeroConfServiceEntry::domain() const { return m_domain; } -/*! Returns the host name of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::hostName() const +/*! Returns the host name of this \l{ZeroConfServiceEntry}.*/ +QString ZeroConfServiceEntry::hostName() const { return m_hostName; } -/*! Returns the port of this \l{AvahiServiceEntry}.*/ -quint16 AvahiServiceEntry::port() const +/*! Returns the port of this \l{ZeroConfServiceEntry}.*/ +quint16 ZeroConfServiceEntry::port() const { return m_port; } -/*! Returns the network protocol of this \l{AvahiServiceEntry}.*/ -QAbstractSocket::NetworkLayerProtocol AvahiServiceEntry::protocol() const +/*! Returns the network protocol of this \l{ZeroConfServiceEntry}.*/ +QAbstractSocket::NetworkLayerProtocol ZeroConfServiceEntry::protocol() const { return m_protocol; } -/*! Returns the avahi flags of this \l{AvahiServiceEntry}.*/ -AvahiLookupResultFlags AvahiServiceEntry::flags() const -{ - return m_flags; -} - -/*! Returns the txt string list of this \l{AvahiServiceEntry}.*/ -QStringList AvahiServiceEntry::txt() const +/*! Returns the txt string list of this \l{ZeroConfServiceEntry}.*/ +QStringList ZeroConfServiceEntry::txt() const { return m_txt; } -/*! Returns true if this \l{AvahiServiceEntry} is valid.*/ -bool AvahiServiceEntry::isValid() const +/*! Returns true if this \l{ZeroConfServiceEntry} is valid.*/ +bool ZeroConfServiceEntry::isValid() const { return !m_hostAddress.isNull() && !m_hostName.isEmpty() && m_port != 0 && m_protocol != QAbstractSocket::UnknownNetworkLayerProtocol; } -/*! Returns true if this \l{AvahiServiceEntry} is cached.*/ -bool AvahiServiceEntry::isChached() const +/*! Returns true if this \l{ZeroConfServiceEntry} is cached.*/ +bool ZeroConfServiceEntry::isChached() const { - return m_flags & AVAHI_LOOKUP_RESULT_CACHED; + return m_isCached; } -/*! Returns true if this \l{AvahiServiceEntry} was found in the wide area.*/ -bool AvahiServiceEntry::isWideArea() const +/*! Returns true if this \l{ZeroConfServiceEntry} was found in the wide area.*/ +bool ZeroConfServiceEntry::isWideArea() const { - return m_flags & AVAHI_LOOKUP_RESULT_WIDE_AREA; + return m_isWideArea; } -/*! Returns true if this \l{AvahiServiceEntry} is a multicast service.*/ -bool AvahiServiceEntry::isMulticast() const +/*! Returns true if this \l{ZeroConfServiceEntry} is a multicast service.*/ +bool ZeroConfServiceEntry::isMulticast() const { - return m_flags & AVAHI_LOOKUP_RESULT_MULTICAST; + return m_isMulticast; } -/*! Returns true if this \l{AvahiServiceEntry} was found local.*/ -bool AvahiServiceEntry::isLocal() const +/*! Returns true if this \l{ZeroConfServiceEntry} was found local.*/ +bool ZeroConfServiceEntry::isLocal() const { - return m_flags & AVAHI_LOOKUP_RESULT_LOCAL; + return m_isLocal; } -/*! Returns true if this \l{AvahiServiceEntry} is our own service.*/ -bool AvahiServiceEntry::isOurOwn() const +/*! Returns true if this \l{ZeroConfServiceEntry} is our own service.*/ +bool ZeroConfServiceEntry::isOurOwn() const { - return m_flags & AVAHI_LOOKUP_RESULT_OUR_OWN; + return m_isOurOwn; } -/*! Returns true if this \l{AvahiServiceEntry} is equal to \a other; otherwise returns false.*/ -bool AvahiServiceEntry::operator ==(const AvahiServiceEntry &other) const +/*! Returns true if this \l{ZeroConfServiceEntry} is equal to \a other; otherwise returns false.*/ +bool ZeroConfServiceEntry::operator ==(const ZeroConfServiceEntry &other) const { return other.name() == m_name && other.serviceType() == m_serviceType && @@ -157,20 +154,24 @@ bool AvahiServiceEntry::operator ==(const AvahiServiceEntry &other) const other.hostName() == m_hostName && other.port() == m_port && other.protocol() == m_protocol && - other.flags() == m_flags && + other.isChached() == m_isCached && + other.isWideArea() == m_isWideArea && + other.isMulticast() == m_isMulticast && + other.isLocal() == m_isLocal && + other.isOurOwn() == m_isOurOwn && other.txt() == m_txt; } -/*! Returns true if this \l{AvahiServiceEntry} is not equal to \a other; otherwise returns false.*/ -bool AvahiServiceEntry::operator !=(const AvahiServiceEntry &other) const +/*! Returns true if this \l{ZeroConfServiceEntry} is not equal to \a other; otherwise returns false.*/ +bool ZeroConfServiceEntry::operator !=(const ZeroConfServiceEntry &other) const { return !operator==(other); } /*! Writes the given \a entry to the specified \a dbg.*/ -QDebug operator <<(QDebug dbg, const AvahiServiceEntry &entry) +QDebug operator <<(QDebug dbg, const ZeroConfServiceEntry &entry) { - dbg.nospace() << "AvahiServiceEntry("; + dbg.nospace() << "ZeroConfServiceEntry("; dbg << entry.name() << ")" << endl; dbg << " location: " << entry.hostAddress().toString() << ":" << entry.port() << endl; dbg << " hostname: " << entry.hostName() << endl; diff --git a/libnymea/network/avahi/avahiserviceentry.h b/libnymea/network/zeroconf/zeroconfserviceentry.h similarity index 74% rename from libnymea/network/avahi/avahiserviceentry.h rename to libnymea/network/zeroconf/zeroconfserviceentry.h index 5a607eea..01b8001e 100644 --- a/libnymea/network/avahi/avahiserviceentry.h +++ b/libnymea/network/zeroconf/zeroconfserviceentry.h @@ -20,23 +20,21 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef AVAHISERVICEENTRY_H -#define AVAHISERVICEENTRY_H +#ifndef ZEROCONFSERVICEENTRY_H +#define ZEROCONFSERVICEENTRY_H #include #include #include #include -#include - #include "libnymea.h" -class LIBNYMEA_EXPORT AvahiServiceEntry +class LIBNYMEA_EXPORT ZeroConfServiceEntry { public: - AvahiServiceEntry(); - AvahiServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags); + ZeroConfServiceEntry(); + ZeroConfServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, bool cached, bool isWideArea, bool isMulticase, bool isLocal, bool isOurOwn); QString name() const; QString serviceType() const; @@ -45,7 +43,6 @@ public: QString hostName() const; quint16 port() const; QAbstractSocket::NetworkLayerProtocol protocol() const; - AvahiLookupResultFlags flags() const; QStringList txt() const; bool isValid() const; @@ -56,8 +53,8 @@ public: bool isLocal() const; bool isOurOwn() const; - bool operator ==(const AvahiServiceEntry &other) const; - bool operator !=(const AvahiServiceEntry &other) const; + bool operator ==(const ZeroConfServiceEntry &other) const; + bool operator !=(const ZeroConfServiceEntry &other) const; private: QString m_name; @@ -68,11 +65,15 @@ private: quint16 m_port; QAbstractSocket::NetworkLayerProtocol m_protocol; QStringList m_txt; - AvahiLookupResultFlags m_flags; + bool m_isCached = false; + bool m_isWideArea = false; + bool m_isMulticast = false; + bool m_isLocal = false; + bool m_isOurOwn = false; }; -QDebug operator <<(QDebug dbg, const AvahiServiceEntry &entry); -Q_DECLARE_METATYPE(AvahiServiceEntry) +QDebug operator <<(QDebug dbg, const ZeroConfServiceEntry &entry); +Q_DECLARE_METATYPE(ZeroConfServiceEntry) -#endif // AVAHISERVICEENTRY_H +#endif // ZEROCONFSERVICEENTRY_H diff --git a/libnymea/network/zeroconf/zeroconfservicepublisher.cpp b/libnymea/network/zeroconf/zeroconfservicepublisher.cpp new file mode 100644 index 00000000..207f1798 --- /dev/null +++ b/libnymea/network/zeroconf/zeroconfservicepublisher.cpp @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zeroconfservicepublisher.h" + +ZeroConfServicePublisher::ZeroConfServicePublisher(QObject *parent) : QObject(parent) +{ + +} + +/*! + * \brief ZeroConfServicePublisher::registerService + * \param id An ID used to track this service instance. Pick a unique id and use the same for updating or unregistering the service + * \param name The name as it should appear on the network. Note that it might be changed when collisions appear + * \param hostAddress The hostAddress the server is running + * \param port The port of the server + * \param serviceType The service type as it should appear on the network, for instance "_http.tcp" + * \param txtRecords A Map of txt records that should be published with this service + * \return + */ + +bool ZeroConfServicePublisher::registerService(const QString &id, const QString &name, const QHostAddress &hostAddress, const quint16 &port, const QString &serviceType, const QHash &txtRecords) +{ + Q_UNUSED(id) + Q_UNUSED(name) + Q_UNUSED(hostAddress) + Q_UNUSED(port) + Q_UNUSED(serviceType) + Q_UNUSED(txtRecords) + return false; +} + +/*! + * \brief ZeroConfServicePublisher::unregisterService + * \param id The id previously used to register the server + */ +void ZeroConfServicePublisher::unregisterService(const QString &id) +{ + Q_UNUSED(id) +} diff --git a/libnymea-core/hardware/network/avahi/qtavahiclient.h b/libnymea/network/zeroconf/zeroconfservicepublisher.h similarity index 55% rename from libnymea-core/hardware/network/avahi/qtavahiclient.h rename to libnymea/network/zeroconf/zeroconfservicepublisher.h index 94d3cd7f..e61d33bc 100644 --- a/libnymea-core/hardware/network/avahi/qtavahiclient.h +++ b/libnymea/network/zeroconf/zeroconfservicepublisher.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2016 Simon Stürz * + * Copyright (C) 2019 Michael Zanetti * * * * This file is part of nymea. * * * @@ -20,59 +20,21 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef QTAVAHICLIENT_H -#define QTAVAHICLIENT_H +#ifndef ZEROCONFSERVICEPUBLISHER_H +#define ZEROCONFSERVICEPUBLISHER_H #include -#include +#include -namespace nymeaserver { - -class QtAvahiClient : public QObject +class ZeroConfServicePublisher : public QObject { Q_OBJECT - Q_ENUMS(QtAvahiClientState) - public: - enum QtAvahiClientState { - QtAvahiClientStateNone, - QtAvahiClientStateRunning, - QtAvahiClientStateFailure, - QtAvahiClientStateCollision, - QtAvahiClientStateRegistering, - QtAvahiClientStateConnecting - }; - - explicit QtAvahiClient(QObject *parent = nullptr); - ~QtAvahiClient(); - - QtAvahiClientState state() const; - -private: - friend class QtAvahiService; - friend class QtAvahiServiceBrowserImplementation; - friend class QtAvahiServiceBrowserImplementationPrivate; - - const AvahiPoll *m_poll; - AvahiClient *m_client; - int error; - QtAvahiClientState m_state; - - void start(); - void stop(); - QString errorString() const; - - static void callback(AvahiClient *client, AvahiClientState state, void *userdata); - -private slots: - void onClientStateChanged(const QtAvahiClientState &state); - -signals: - void clientStateChanged(const QtAvahiClientState &state); - void clientStateChangedInternal(const QtAvahiClientState &state); + explicit ZeroConfServicePublisher(QObject *parent = nullptr); + virtual ~ZeroConfServicePublisher() = default; + virtual bool registerService(const QString &id, const QString &name, const QHostAddress &hostAddress, const quint16 &port, const QString &serviceType, const QHash &txtRecords); + virtual void unregisterService(const QString &id); }; -} - -#endif // QTAVAHICLIENT_H +#endif // ZEROCONFSERVICEPUBLISHER_H diff --git a/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation.h b/libnymea/platform/platformzeroconfcontroller.cpp similarity index 53% rename from libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation.h rename to libnymea/platform/platformzeroconfcontroller.cpp index 1e0260de..3aada70f 100644 --- a/libnymea-core/hardware/network/avahi/qtavahiservicebrowserimplementation.h +++ b/libnymea/platform/platformzeroconfcontroller.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2016 Simon Stürz * + * Copyright (C) 2019 Michael Zanetti * * * * This file is part of nymea. * * * @@ -20,57 +20,24 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef QTAVAHISERVICEBROWSERIMPLEMENTATION_H -#define QTAVAHISERVICEBROWSERIMPLEMENTATION_H +#include "platformzeroconfcontroller.h" -#include -#include +#include "network/zeroconf/zeroconfservicebrowser.h" +#include "network/zeroconf/zeroconfservicepublisher.h" -#include "qtavahiclient.h" - -#include "network/avahi/avahiserviceentry.h" -#include "network/avahi/qtavahiservicebrowser.h" - - -namespace nymeaserver { - -class QtAvahiServiceBrowserImplementationPrivate; - -class QtAvahiServiceBrowserImplementation : public QtAvahiServiceBrowser +PlatformZeroConfController::PlatformZeroConfController(QObject *parent): + QObject(parent) { - Q_OBJECT - - friend class HardwareManagerImplementation; - -public: - explicit QtAvahiServiceBrowserImplementation(QObject *parent = nullptr); - ~QtAvahiServiceBrowserImplementation() override; - - QList serviceEntries() const override; - - bool available() const override; - bool enabled() const override; - -private slots: - void onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state); - -protected: - void setEnabled(bool enabled) override; - -private: - bool m_available = false; - bool m_enabled = false; - - QtAvahiServiceBrowserImplementationPrivate *d_ptr; - - QList m_serviceEntries; - QStringList m_serviceTypes; - - void createServiceBrowser(const char* serviceType); - - Q_DECLARE_PRIVATE(QtAvahiServiceBrowserImplementation) -}; - + m_zeroConfBrowserStub = new ZeroConfServiceBrowser(this); + m_zeroConfPublisherStub = new ZeroConfServicePublisher(this); } -#endif // QTAVAHISERVICEBROWSERIMPLEMENTATION_H +ZeroConfServiceBrowser *PlatformZeroConfController::zeroConfServiceBrowser() const +{ + return m_zeroConfBrowserStub; +} + +ZeroConfServicePublisher *PlatformZeroConfController::zeroConfServicePublisher() const +{ + return m_zeroConfPublisherStub; +} diff --git a/libnymea-core/hardware/network/avahi/qtavahiservice_p.h b/libnymea/platform/platformzeroconfcontroller.h similarity index 64% rename from libnymea-core/hardware/network/avahi/qtavahiservice_p.h rename to libnymea/platform/platformzeroconfcontroller.h index 7f51f468..937de16a 100644 --- a/libnymea-core/hardware/network/avahi/qtavahiservice_p.h +++ b/libnymea/platform/platformzeroconfcontroller.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2016 Simon Stürz * + * Copyright (C) 2019 Michael Zanetti * * * * This file is part of nymea. * * * @@ -20,43 +20,29 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef QTAVAHISERVICEPRIVATE_P -#define QTAVAHISERVICEPRIVATE_P +#ifndef PLATFORMZEROCONFCONTROLLER_H +#define PLATFORMZEROCONFCONTROLLER_H #include -#include -#include "qtavahiservice.h" -#include "qtavahiclient.h" +class ZeroConfServiceBrowser; +class ZeroConfServicePublisher; -#include -#include -#include - -namespace nymeaserver { - -class QtAvahiServicePrivate +class PlatformZeroConfController: public QObject { + Q_OBJECT public: - QtAvahiServicePrivate(); + explicit PlatformZeroConfController(QObject *parent = nullptr); + virtual ~PlatformZeroConfController() = default; - static void callback(AvahiEntryGroup *group, AvahiEntryGroupState state, void *userdata); - - QtAvahiClient *client; - AvahiEntryGroup *group; - AvahiStringList *serviceList = nullptr; - QString name; - QHostAddress hostAddress; - quint16 port; - QString type; - QHash txtRecords; - int error; - - static AvahiStringList *createTxtList(const QHash &txt); + virtual ZeroConfServiceBrowser *zeroConfServiceBrowser() const; + virtual ZeroConfServicePublisher *zeroConfServicePublisher() const; +private: + ZeroConfServiceBrowser *m_zeroConfBrowserStub = nullptr; + ZeroConfServicePublisher *m_zeroConfPublisherStub = nullptr; }; -} - -#endif // QTAVAHISERVICEPRIVATE_P +Q_DECLARE_INTERFACE(PlatformZeroConfController, "io.nymea.PlatformZeroConfController") +#endif // PLATFORMZEROCONFCONTROLLER_H diff --git a/tests/auto/autotests.pri b/tests/auto/autotests.pri index 118764ad..b8fed33b 100644 --- a/tests/auto/autotests.pri +++ b/tests/auto/autotests.pri @@ -8,7 +8,7 @@ INCLUDEPATH += $$top_srcdir/libnymea \ LIBS += -L$$top_builddir/libnymea/ -lnymea \ -L$$top_builddir/libnymea-core/ -lnymea-core \ -L$$top_builddir/plugins/mock/ \ - -lssl -lcrypto -lavahi-common -lavahi-client -lnymea-remoteproxyclient + -lssl -lcrypto -lnymea-remoteproxyclient SOURCES += ../nymeatestbase.cpp \