diff --git a/debian/changelog b/debian/changelog index f0270cc6..a014f8ba 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ guh (0.7.2) xenial; urgency=medium * Add Avahi support + * Add guh-plugins-maker package -- Simon Stürz Thu, 28 Apr 2016 14:56:17 +0200 diff --git a/debian/control b/debian/control index f10bf959..7556dec1 100644 --- a/debian/control +++ b/debian/control @@ -142,3 +142,17 @@ Description: Plugins for guh IoT server - 6LoWPAN Merkur boards for your environment. This package contains plugins for the 6LoWPAN Merkur board. +Package: guh-plugins-maker +Section: libs +Architecture: any +Depends: libguh1 (= ${binary:Version}), + guhd (= ${binary:Version}), + ${shlibs:Depends}, + ${misc:Depends} +Description: Plugins for guh IoT server - for maker, tinker and hackers + guh is an open source IoT (Internet of Things) server, + which allows to control a lot of different devices from many different + manufacturers. With the powerful rule engine you are able to connect any + device available in the system and create individual scenes and behaviors + for your environment. This package contains plugins for the 6LoWPAN Merkur + board. diff --git a/debian/copyright b/debian/copyright index 0a13c3d9..56ba682c 100644 --- a/debian/copyright +++ b/debian/copyright @@ -17,12 +17,6 @@ Copyright: (C) 2014 Michael Zanetti 2014 Simon Stürz License: GPL-2+ -Files: libguh/avahi/zconf* -Copyright: (c) 2012 Johannes Hilden - 2016 Simon Stürz -License: LGPL-2.1 - - Files: libguh/avahi/qt-watch* Copyright: (c) avahi 2016 Simon Stürz diff --git a/debian/guh-plugins-maker.dirs b/debian/guh-plugins-maker.dirs new file mode 100644 index 00000000..0a803bb8 --- /dev/null +++ b/debian/guh-plugins-maker.dirs @@ -0,0 +1 @@ +usr/lib/guh/plugins diff --git a/debian/guh-plugins-maker.install b/debian/guh-plugins-maker.install new file mode 100644 index 00000000..f08eaa81 --- /dev/null +++ b/debian/guh-plugins-maker.install @@ -0,0 +1,5 @@ +usr/lib/guh/plugins/libguh_devicepluginavahimonitor.so +usr/lib/guh/plugins/libguh_devicepluginlircd.so +usr/lib/guh/plugins/libguh_devicepluginwifidetector.so +usr/lib/guh/plugins/libguh_deviceplugincommandlauncher.so +usr/lib/guh/plugins/libguh_devicepluginudpcommander.so diff --git a/debian/guh-plugins.install b/debian/guh-plugins.install index 8678448c..64348bc2 100644 --- a/debian/guh-plugins.install +++ b/debian/guh-plugins.install @@ -3,21 +3,16 @@ usr/lib/guh/plugins/libguh_devicepluginelro.so usr/lib/guh/plugins/libguh_deviceplugineq3.so usr/lib/guh/plugins/libguh_devicepluginintertechno.so usr/lib/guh/plugins/libguh_devicepluginlgsmarttv.so -usr/lib/guh/plugins/libguh_devicepluginlircd.so usr/lib/guh/plugins/libguh_devicepluginmailnotification.so usr/lib/guh/plugins/libguh_devicepluginopenweathermap.so usr/lib/guh/plugins/libguh_devicepluginphilipshue.so usr/lib/guh/plugins/libguh_devicepluginwakeonlan.so usr/lib/guh/plugins/libguh_devicepluginwemo.so -usr/lib/guh/plugins/libguh_devicepluginwifidetector.so usr/lib/guh/plugins/libguh_deviceplugindatetime.so -usr/lib/guh/plugins/libguh_deviceplugincommandlauncher.so usr/lib/guh/plugins/libguh_devicepluginunitec.so usr/lib/guh/plugins/libguh_devicepluginleynew.so -usr/lib/guh/plugins/libguh_devicepluginudpcommander.so usr/lib/guh/plugins/libguh_devicepluginkodi.so usr/lib/guh/plugins/libguh_devicepluginelgato.so usr/lib/guh/plugins/libguh_devicepluginawattar.so usr/lib/guh/plugins/libguh_devicepluginnetatmo.so usr/lib/guh/plugins/libguh_deviceplugindenon.so - diff --git a/debian/guhd.1 b/debian/guhd.1 index d3506fe4..e871f6d8 100644 --- a/debian/guhd.1 +++ b/debian/guhd.1 @@ -1,6 +1,6 @@ .\" Manpage for guhd. .\" Contact simon.stuerz@guh.guru to correct errors or typos. -.TH man 1 "January 2016" "1.4" "guhd man page" +.TH man 1 "May 2016" "1.5" "guhd man page" .SH NAME guhd \- An open source IoT (Internet of Things) server .SH SYNOPSIS @@ -36,19 +36,21 @@ categories will be printed unless they are explicitly muted with "NoWarnings". \fBMain\ debug\ categories:\fR .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 \fIConnection\fR\ (default\ enabled) Print the debug messages from the TCP connections in guh. .IP \fIDeviceManager\fR\ (default\ enabled) Print the debug messages from the device manager. .IP \fIHardware\fR\ (default\ disabled) Print the debug messages from hardware resources in guh. -.IP \fIJsonRpc\fR\ (default\ enabled) +.IP \fIJsonRpc\fR\ (default\ disabled) Print the debug messages from JSON-RPC API. .IP \fILogEngine\fR\ (default\ disabled) Print the debug messages from logging engine. .IP \fIOAuth2\fR\ (default\ disabled) Print the debug messages of the OAuth2 resource. -.IP \fIRest\fR\ (default\ enabled) +.IP \fIRest\fR\ (default\ disabled) Print the debug messages from REST API. .IP \fIRuleEngine\fR\ (default\ enabled) Print the debug messages from the rule engine. @@ -56,9 +58,9 @@ Print the debug messages from the rule engine. Print the debug messages from the TCP server. .IP \fIWarning\fR\ (default\ enabled) Print warnings. -.IP \fIWebServer\fR\ (default\ enabled) +.IP \fIWebServer\fR\ (default\ disabled) Print the debug messages from the web server. -.IP \fIWebSocketServer\fR\ (default\ enabled) +.IP \fIWebSocketServer\fR\ (default\ disabled) Print the debug messages from the websocket server. .TP \fBDebug\ categories\ for\ plugins:\fR diff --git a/libguh/devicemanager.cpp b/libguh/devicemanager.cpp index 579946f6..672170cb 100644 --- a/libguh/devicemanager.cpp +++ b/libguh/devicemanager.cpp @@ -206,7 +206,6 @@ DeviceManager::DeviceManager(QObject *parent) : m_radio433 = new Radio433(this); m_radio433->enable(); - // TODO: error handling if no Radio433 detected (GPIO or network), disable radio433 plugins or something... m_networkManager = new NetworkManager(this); connect(m_networkManager, &NetworkManager::replyReady, this, &DeviceManager::replyReady); @@ -216,6 +215,10 @@ DeviceManager::DeviceManager(QObject *parent) : connect(m_upnpDiscovery, &UpnpDiscovery::discoveryFinished, this, &DeviceManager::upnpDiscoveryFinished); connect(m_upnpDiscovery, &UpnpDiscovery::upnpNotify, this, &DeviceManager::upnpNotifyReceived); + // Avahi Browser + m_avahiBrowser = new QtAvahiServiceBrowser(this); + m_avahiBrowser->enable(); + // Bluetooth LE #ifdef BLUETOOTH_LE m_bluetoothScanner = new BluetoothScanner(this); @@ -587,7 +590,7 @@ DeviceManager::DeviceError DeviceManager::pairDevice(const PairingTransactionId DevicePlugin *plugin = m_devicePlugins.value(m_supportedDevices.value(deviceClassId).pluginId()); if (!plugin) { - qWarning() << "Can't find a plugin for this device class"; + qCWarning(dcDeviceManager()) << "Can't find a plugin for this device class"; return DeviceErrorPluginNotFound; } @@ -1007,7 +1010,7 @@ void DeviceManager::loadPlugins() m_devicePlugins.insert(pluginIface->pluginId(), pluginIface); connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::eventTriggered); - connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered); + connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered, Qt::QueuedConnection); connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished); connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished); connect(pluginIface, &DevicePlugin::pairingFinished, this, &DeviceManager::slotPairingFinished); @@ -1332,6 +1335,7 @@ void DeviceManager::replyReady(const PluginId &pluginId, QNetworkReply *reply) } } } + void DeviceManager::upnpDiscoveryFinished(const QList &deviceDescriptorList, const PluginId &pluginId) { foreach (DevicePlugin *devicePlugin, m_devicePlugins) { diff --git a/libguh/devicemanager.h b/libguh/devicemanager.h index 2b93dd03..f1d06198 100644 --- a/libguh/devicemanager.h +++ b/libguh/devicemanager.h @@ -35,6 +35,7 @@ #include "network/networkmanager.h" #include "network/upnp/upnpdiscovery.h" #include "network/upnp/upnpdevicedescriptor.h" +#include "network/avahi/qtavahiservicebrowser.h" #ifdef BLUETOOTH_LE #include "bluetooth/bluetoothscanner.h" @@ -201,6 +202,8 @@ private: QTimer m_pluginTimer; QList m_pluginTimerUsers; NetworkManager *m_networkManager; + UpnpDiscovery* m_upnpDiscovery; + QtAvahiServiceBrowser *m_avahiBrowser; #ifdef BLUETOOTH_LE BluetoothScanner *m_bluetoothScanner; diff --git a/libguh/libguh.pro b/libguh/libguh.pro index 84cd4f47..458d7492 100644 --- a/libguh/libguh.pro +++ b/libguh/libguh.pro @@ -48,9 +48,11 @@ HEADERS += devicemanager.h \ network/oauth2.h \ network/avahi/qt-watch.h \ network/avahi/avahiserviceentry.h \ - network/avahi/zconfservicebrowser.h \ - network/avahi/zconfserviceclient.h \ - network/avahi/zconfservice.h \ + network/avahi/qtavahiclient.h \ + network/avahi/qtavahiservice.h \ + network/avahi/qtavahiservice_p.h \ + network/avahi/qtavahiservicebrowser.h \ + network/avahi/qtavahiservicebrowser_p.h \ coap/coap.h \ coap/coappdu.h \ coap/coapoption.h \ @@ -74,8 +76,6 @@ HEADERS += devicemanager.h \ types/ruleaction.h \ types/ruleactionparam.h \ types/statedescriptor.h \ - network/avahi/guhavahibrowser.h - SOURCES += devicemanager.cpp \ loggingcategories.cpp \ @@ -99,9 +99,11 @@ SOURCES += devicemanager.cpp \ network/oauth2.cpp \ network/avahi/qt-watch.cpp \ network/avahi/avahiserviceentry.cpp \ - network/avahi/zconfservicebrowser.cpp \ - network/avahi/zconfserviceclient.cpp \ - network/avahi/zconfservice.cpp \ + network/avahi/qtavahiclient.cpp \ + network/avahi/qtavahiservice.cpp \ + network/avahi/qtavahiservice_p.cpp \ + network/avahi/qtavahiservicebrowser.cpp \ + network/avahi/qtavahiservicebrowser_p.cpp \ coap/coap.cpp \ coap/coappdu.cpp \ coap/coapoption.cpp \ @@ -125,8 +127,6 @@ SOURCES += devicemanager.cpp \ types/ruleaction.cpp \ types/ruleactionparam.cpp \ types/statedescriptor.cpp \ - network/avahi/guhavahibrowser.cpp - # install plugininfo python script for libguh-dev generateplugininfo.files = $$top_srcdir/plugins/guh-generateplugininfo diff --git a/libguh/loggingcategories.cpp b/libguh/loggingcategories.cpp index aac01cda..8ba77a66 100644 --- a/libguh/loggingcategories.cpp +++ b/libguh/loggingcategories.cpp @@ -33,3 +33,4 @@ Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer") Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc") Q_LOGGING_CATEGORY(dcRest, "Rest") Q_LOGGING_CATEGORY(dcOAuth2, "OAuth2") +Q_LOGGING_CATEGORY(dcAvahi, "Avahi") diff --git a/libguh/loggingcategories.h b/libguh/loggingcategories.h index c90cdcca..b75d0051 100644 --- a/libguh/loggingcategories.h +++ b/libguh/loggingcategories.h @@ -40,5 +40,6 @@ Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServer) Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc) Q_DECLARE_LOGGING_CATEGORY(dcRest) Q_DECLARE_LOGGING_CATEGORY(dcOAuth2) +Q_DECLARE_LOGGING_CATEGORY(dcAvahi) #endif // LOGGINGCATEGORYS_H diff --git a/libguh/network/avahi/avahiserviceentry.cpp b/libguh/network/avahi/avahiserviceentry.cpp index e6885363..bf16a0fe 100644 --- a/libguh/network/avahi/avahiserviceentry.cpp +++ b/libguh/network/avahi/avahiserviceentry.cpp @@ -18,19 +18,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/*! - \class AvahiServiceEntry - \brief Holds information about an avahi service entry. - - \ingroup types - \inmodule libguh - -*/ - #include "avahiserviceentry.h" - -/*! Constructs an empty invalid \l{AvahiServiceEntry}*/ AvahiServiceEntry::AvahiServiceEntry() : m_port(0), m_protocol(QAbstractSocket::UnknownNetworkLayerProtocol) @@ -38,9 +27,9 @@ AvahiServiceEntry::AvahiServiceEntry() : } -/*! Constructs a new \l{AvahiServiceEntry} with the given \a name, \a hostAddress, \a domain, \a hostName, \a port, \a protocol, \a txt and \a flags.*/ -AvahiServiceEntry::AvahiServiceEntry(QString name, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags) : +AvahiServiceEntry::AvahiServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags) : m_name(name), + m_serviceType(serviceType), m_hostAddress(hostAddress), m_domain(domain), m_hostName(hostName), @@ -52,82 +41,109 @@ AvahiServiceEntry::AvahiServiceEntry(QString name, QHostAddress hostAddress, QSt } -/*! Returns the name of this \l{AvahiServiceEntry}.*/ QString AvahiServiceEntry::name() const { return m_name; } +QString AvahiServiceEntry::serviceType() const +{ + return m_serviceType; +} -/*! Returns the host address of this \l{AvahiServiceEntry}.*/ QHostAddress AvahiServiceEntry::hostAddress() const { return m_hostAddress; } -/*! Returns the domain of this \l{AvahiServiceEntry}.*/ QString AvahiServiceEntry::domain() const { return m_domain; } -/*! Returns the host name of this \l{AvahiServiceEntry}.*/ QString AvahiServiceEntry::hostName() const { return m_hostName; } -/*! Returns the port of this \l{AvahiServiceEntry}.*/ quint16 AvahiServiceEntry::port() const { return m_port; } -/*! Returns the protocol of this \l{AvahiServiceEntry}.*/ QAbstractSocket::NetworkLayerProtocol AvahiServiceEntry::protocol() const { return m_protocol; } -/*! Returns the txt string list of this \l{AvahiServiceEntry}.*/ +AvahiLookupResultFlags AvahiServiceEntry::flags() const +{ + return m_flags; +} + QStringList AvahiServiceEntry::txt() const { return m_txt; } -/*! Returns true if this \l{AvahiServiceEntry} is valid.*/ bool AvahiServiceEntry::isValid() const { return !m_hostAddress.isNull() && !m_hostName.isEmpty() && m_port != 0 && m_protocol != QAbstractSocket::UnknownNetworkLayerProtocol; } -/*! Returns true if this \l{AvahiServiceEntry} was loaded from the cache.*/ bool AvahiServiceEntry::isChached() const { return m_flags & AVAHI_LOOKUP_RESULT_CACHED; } -/*! Returns true if this \l{AvahiServiceEntry} was found in the wide area.*/ bool AvahiServiceEntry::isWideArea() const { return m_flags & AVAHI_LOOKUP_RESULT_WIDE_AREA; } -/*! Returns true if this \l{AvahiServiceEntry} is a multicast service.*/ bool AvahiServiceEntry::isMulticast() const { return m_flags & AVAHI_LOOKUP_RESULT_MULTICAST; } -/*! Returns true if this \l{AvahiServiceEntry} was found local.*/ bool AvahiServiceEntry::isLocal() const { return m_flags & AVAHI_LOOKUP_RESULT_LOCAL; } -/*! Returns true if this \l{AvahiServiceEntry} is our own service.*/ bool AvahiServiceEntry::isOurOwn() const { return m_flags & AVAHI_LOOKUP_RESULT_OUR_OWN; } +bool AvahiServiceEntry::operator ==(const AvahiServiceEntry &other) const +{ + return other.name() == m_name && + other.serviceType() == m_serviceType && + other.hostAddress() == m_hostAddress && + other.domain() == m_domain && + other.hostName() == m_hostName && + other.port() == m_port && + other.protocol() == m_protocol && + other.flags() == m_flags && + other.txt() == m_txt; +} + +bool AvahiServiceEntry::operator !=(const AvahiServiceEntry &other) const +{ + return !operator==(other); +} + + +QDebug operator <<(QDebug dbg, const AvahiServiceEntry &entry) +{ + dbg.nospace() << "AvahiServiceEntry("; + dbg << entry.name() << ")" << endl; + dbg << " location: " << entry.hostAddress().toString() << ":" << entry.port() << endl; + dbg << " hostname: " << entry.hostName() << endl; + dbg << " domain: " << entry.domain() << endl; + dbg << "service type: " << entry.serviceType() << endl; + dbg << " protocol: " << entry.protocol() << endl; + dbg << " txt: " << entry.txt() << endl; + return dbg; +} diff --git a/libguh/network/avahi/avahiserviceentry.h b/libguh/network/avahi/avahiserviceentry.h index 07740fb6..13d340a6 100644 --- a/libguh/network/avahi/avahiserviceentry.h +++ b/libguh/network/avahi/avahiserviceentry.h @@ -24,20 +24,25 @@ #include #include #include +#include #include -class AvahiServiceEntry +#include "libguh.h" + +class LIBGUH_EXPORT AvahiServiceEntry { public: AvahiServiceEntry(); - AvahiServiceEntry(QString name, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags); + AvahiServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags); QString name() const; + QString serviceType() const; QHostAddress hostAddress() const; QString domain() const; QString hostName() const; quint16 port() const; QAbstractSocket::NetworkLayerProtocol protocol() const; + AvahiLookupResultFlags flags() const; QStringList txt() const; bool isValid() const; @@ -48,8 +53,12 @@ public: bool isLocal() const; bool isOurOwn() const; + bool operator ==(const AvahiServiceEntry &other) const; + bool operator !=(const AvahiServiceEntry &other) const; + private: QString m_name; + QString m_serviceType; QHostAddress m_hostAddress; QString m_domain; QString m_hostName; @@ -60,4 +69,7 @@ private: }; +QDebug operator <<(QDebug dbg, const AvahiServiceEntry &entry); +Q_DECLARE_METATYPE(AvahiServiceEntry) + #endif // AVAHISERVICEENTRY_H diff --git a/libguh/network/avahi/qt-watch.cpp b/libguh/network/avahi/qt-watch.cpp index b39fc080..f542510a 100644 --- a/libguh/network/avahi/qt-watch.cpp +++ b/libguh/network/avahi/qt-watch.cpp @@ -1,8 +1,6 @@ /*** This file is part of avahi. - Modified: (C) 2016 Simon Stürz - 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 @@ -18,6 +16,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + Modified: (C) 2016 Simon Stürz + ***/ #include diff --git a/libguh/network/avahi/qt-watch.h b/libguh/network/avahi/qt-watch.h index 6cde472b..ea5c1fc5 100644 --- a/libguh/network/avahi/qt-watch.h +++ b/libguh/network/avahi/qt-watch.h @@ -4,8 +4,6 @@ /*** This file is part of avahi. - Modified: (C) 2016 Simon Stürz - 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 @@ -19,6 +17,8 @@ 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 */ diff --git a/libguh/network/avahi/qtavahiclient.cpp b/libguh/network/avahi/qtavahiclient.cpp new file mode 100644 index 00000000..d67133d0 --- /dev/null +++ b/libguh/network/avahi/qtavahiclient.cpp @@ -0,0 +1,80 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "qtavahiclient.h" +#include "qt-watch.h" + +#include + +QtAvahiClient::QtAvahiClient(QObject *parent) : + QObject(parent), + poll(avahi_qt_poll_get()), + client(0), + error(0) +{ + +} + +QtAvahiClient::~QtAvahiClient() +{ + if (client) + avahi_client_free(client); +} + +void QtAvahiClient::start() +{ + if (client) + return; + + avahi_client_new(poll, (AvahiClientFlags) 0, QtAvahiClient::callback, this, &error); +} + +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->client = client; + + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + emit serviceClient->clientStateChanged(QtAvahiClientStateRunning); + break; + case AVAHI_CLIENT_FAILURE: + emit serviceClient->clientStateChanged(QtAvahiClientStateFailure); + break; + case AVAHI_CLIENT_S_COLLISION: + emit serviceClient->clientStateChanged(QtAvahiClientStateCollision); + break; + case AVAHI_CLIENT_S_REGISTERING: + emit serviceClient->clientStateChanged(QtAvahiClientStateRegistering); + break; + case AVAHI_CLIENT_CONNECTING: + emit serviceClient->clientStateChanged(QtAvahiClientStateConnecting); + break; + } +} + diff --git a/libguh/network/avahi/qtavahiclient.h b/libguh/network/avahi/qtavahiclient.h new file mode 100644 index 00000000..8500ca2b --- /dev/null +++ b/libguh/network/avahi/qtavahiclient.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef QTAVAHICLIENT_H +#define QTAVAHICLIENT_H + +#include +#include + +#include "libguh.h" + +class LIBGUH_EXPORT QtAvahiClient : public QObject +{ + Q_OBJECT + Q_ENUMS(QtAvahiClientState) + +public: + enum QtAvahiClientState { + QtAvahiClientStateRunning, + QtAvahiClientStateFailure, + QtAvahiClientStateCollision, + QtAvahiClientStateRegistering, + QtAvahiClientStateConnecting + }; + + explicit QtAvahiClient(QObject *parent = 0); + ~QtAvahiClient(); + +private: + friend class QtAvahiService; + friend class QtAvahiServiceBrowser; + friend class QtAvahiServiceBrowserPrivate; + + const AvahiPoll *poll; + AvahiClient *client; + int error; + + void start(); + QString errorString() const; + + static void callback(AvahiClient *client, AvahiClientState state, void *userdata); + +signals: + void clientStateChanged(const QtAvahiClientState &state); + +}; + +#endif // QTAVAHICLIENT_H diff --git a/libguh/network/avahi/qtavahiservice.cpp b/libguh/network/avahi/qtavahiservice.cpp new file mode 100644 index 00000000..74888ee3 --- /dev/null +++ b/libguh/network/avahi/qtavahiservice.cpp @@ -0,0 +1,113 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "qtavahiservice.h" +#include "qtavahiservice_p.h" + +QtAvahiService::QtAvahiService(QObject *parent) : + QObject(parent), + d_ptr(new QtAvahiServicePrivate) +{ + d_ptr->client = new QtAvahiClient(this); + d_ptr->client->start(); +} + +QtAvahiService::~QtAvahiService() +{ + if (d_ptr->group) + avahi_entry_group_free(d_ptr->group); + + delete d_ptr; +} + +quint16 QtAvahiService::port() const +{ + return d_ptr->port; +} + +QString QtAvahiService::name() const +{ + return d_ptr->name; +} + +QString QtAvahiService::serviceType() const +{ + return d_ptr->type; +} + +bool QtAvahiService::registerService(QString name, quint16 port, QString type) +{ + // check if the client is running + if (!d_ptr->client->client || AVAHI_CLIENT_S_RUNNING != avahi_client_get_state(d_ptr->client->client)) + return false; + + d_ptr->name = name; + d_ptr->port = port; + d_ptr->type = type; + + // if the group is not set yet, create it + if (!d_ptr->group) + d_ptr->group = avahi_entry_group_new(d_ptr->client->client, QtAvahiServicePrivate::callback, this); + + // if the group is empty + if (avahi_entry_group_is_empty(d_ptr->group)) { + // add the service + d_ptr->error = avahi_entry_group_add_service(d_ptr->group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + (AvahiPublishFlags) 0, + d_ptr->name.toLatin1().data(), + d_ptr->type.toLatin1().data(), + 0, + 0, + (uint16_t)d_ptr->port, + NULL); + + // verify if the group has to be comitted + if (!d_ptr->error) + d_ptr->error = avahi_entry_group_commit(d_ptr->group); + + // if the group could not be commited, return false + if (d_ptr->error) + return false; + + } + + return true; +} + +void QtAvahiService::resetService() +{ + avahi_entry_group_reset(d_ptr->group); +} + +bool QtAvahiService::isValid() const +{ + return (d_ptr->group && !d_ptr->error); +} + +QString QtAvahiService::errorString() const +{ + if (!d_ptr->client->client) + return "Invalid client."; + + return avahi_strerror(avahi_client_errno(d_ptr->client->client)); +} + diff --git a/libguh/network/avahi/qtavahiservice.h b/libguh/network/avahi/qtavahiservice.h new file mode 100644 index 00000000..c645e9dd --- /dev/null +++ b/libguh/network/avahi/qtavahiservice.h @@ -0,0 +1,68 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef QTAVAHISERVICE_H +#define QTAVAHISERVICE_H + +#include + +#include "libguh.h" + +class QtAvahiServicePrivate; + +class LIBGUH_EXPORT QtAvahiService : public QObject +{ + Q_OBJECT + Q_ENUMS(QtAvahiServiceState) + +public: + enum QtAvahiServiceState { + QtAvahiServiceStateUncomitted, + QtAvahiServiceStateRegistering, + QtAvahiServiceStateEstablished, + QtAvahiServiceStateCollision, + QtAvahiServiceStateFailure + }; + + explicit QtAvahiService(QObject *parent = 0); + ~QtAvahiService(); + + quint16 port() const; + QString name() const; + QString serviceType() const; + + bool registerService(QString name, quint16 port, QString type = "_http._tcp"); + void resetService(); + + bool isValid() const; + QString errorString() const; + +signals: + void serviceStateChanged(const QtAvahiServiceState &state); + +protected: + QtAvahiServicePrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QtAvahiService) + +}; + +#endif // QTAVAHISERVICE_H diff --git a/libguh/network/avahi/guhavahibrowser.cpp b/libguh/network/avahi/qtavahiservice_p.cpp similarity index 57% rename from libguh/network/avahi/guhavahibrowser.cpp rename to libguh/network/avahi/qtavahiservice_p.cpp index 3aff37c5..341228fc 100644 --- a/libguh/network/avahi/guhavahibrowser.cpp +++ b/libguh/network/avahi/qtavahiservice_p.cpp @@ -18,38 +18,39 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "guhavahibrowser.h" -#include "loggingcategories.h" +#include "qtavahiservice_p.h" -GuhAvahiBrowser::GuhAvahiBrowser(QObject *parent) : QObject(parent) +QtAvahiServicePrivate::QtAvahiServicePrivate() : + client(0), + group(0), + error(0) { - m_browser = new ZConfServiceBrowser(this); - connect(m_browser, &ZConfServiceBrowser::serviceEntryAdded, this, &GuhAvahiBrowser::onSeviceAdded); - connect(m_browser, &ZConfServiceBrowser::serviceEntryRemoved, this, &GuhAvahiBrowser::onSeviceRemoved); - connect(m_browser, &ZConfServiceBrowser::serviceBrowsingFinished, this, &GuhAvahiBrowser::onSeviceBrowsingFinished); } -void GuhAvahiBrowser::browseService(const QString &serviceType) +void QtAvahiServicePrivate::callback(AvahiEntryGroup *group, AvahiEntryGroupState state, void *userdata) { - m_serviceEntries.clear(); - m_browser->browse(serviceType); -} - -void GuhAvahiBrowser::onSeviceAdded(const QString &name) -{ - qCDebug(dcHardware()) << QString("Avahi: +%1").arg(name); - m_serviceEntries.append(m_browser->serviceEntry(name)); -} - -void GuhAvahiBrowser::onSeviceRemoved(const QString &name) -{ - qCDebug(dcHardware()) << QString("Avahi: -%1").arg(name); -} - -void GuhAvahiBrowser::onSeviceBrowsingFinished() -{ - qCDebug(dcHardware()) << "Avahi: discovery finished."; - emit avahiBrowseFinished(m_serviceEntries); + Q_UNUSED(group); + QtAvahiService *service = static_cast(userdata); + if (!service) + return; + + switch (state) { + case AVAHI_ENTRY_GROUP_UNCOMMITED: + emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateUncomitted); + 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; + } } diff --git a/libguh/network/avahi/guhavahibrowser.h b/libguh/network/avahi/qtavahiservice_p.h similarity index 71% rename from libguh/network/avahi/guhavahibrowser.h rename to libguh/network/avahi/qtavahiservice_p.h index 688c4fba..e20c2e1a 100644 --- a/libguh/network/avahi/guhavahibrowser.h +++ b/libguh/network/avahi/qtavahiservice_p.h @@ -18,33 +18,35 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef GUHAVAHIBROWSER_H -#define GUHAVAHIBROWSER_H +#ifndef QTAVAHISERVICEPRIVATE_P +#define QTAVAHISERVICEPRIVATE_P #include +#include -#include "zconfservicebrowser.h" +#include "qtavahiservice.h" +#include "qtavahiclient.h" -class GuhAvahiBrowser : public QObject +#include "libguh.h" + +#include +#include +#include + +class LIBGUH_EXPORT QtAvahiServicePrivate { - Q_OBJECT public: - explicit GuhAvahiBrowser(QObject *parent = 0); + QtAvahiServicePrivate(); - void browseService(const QString &serviceType); - -private: - ZConfServiceBrowser *m_browser; - QList m_serviceEntries; - -signals: - void avahiBrowseFinished(const QList &serviceEntries); - -private slots: - void onSeviceAdded(const QString &name); - void onSeviceRemoved(const QString &name); - void onSeviceBrowsingFinished(); + static void callback(AvahiEntryGroup *group, AvahiEntryGroupState state, void *userdata); + QtAvahiClient *client; + AvahiEntryGroup *group; + QString name; + quint16 port; + QString type; + int error; }; -#endif // GUHAVAHIBROWSER_H +#endif // QTAVAHISERVICEPRIVATE_P + diff --git a/libguh/network/avahi/qtavahiservicebrowser.cpp b/libguh/network/avahi/qtavahiservicebrowser.cpp new file mode 100644 index 00000000..e5c93895 --- /dev/null +++ b/libguh/network/avahi/qtavahiservicebrowser.cpp @@ -0,0 +1,81 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "qtavahiservicebrowser.h" +#include "qtavahiservicebrowser_p.h" +#include "loggingcategories.h" + +#include + +QtAvahiServiceBrowser::QtAvahiServiceBrowser(QObject *parent) : + QObject(parent), + d_ptr(new QtAvahiServiceBrowserPrivate(new QtAvahiClient)) +{ + connect(d_ptr->client, &QtAvahiClient::clientStateChanged, this, &QtAvahiServiceBrowser::onClientStateChanged); +} + +QtAvahiServiceBrowser::~QtAvahiServiceBrowser() +{ + // 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; +} + +void QtAvahiServiceBrowser::enable() +{ + d_ptr->client->start(); +} + +QList QtAvahiServiceBrowser::serviceEntries() const +{ + return m_serviceEntries; +} + +void QtAvahiServiceBrowser::onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state) +{ + if (state == QtAvahiClient::QtAvahiClientStateRunning) { + qCDebug(dcAvahi()) << "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->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, (AvahiLookupFlags) 0, QtAvahiServiceBrowserPrivate::callbackServiceTypeBrowser, this); + } else if (state == QtAvahiClient::QtAvahiClientStateFailure) { + qCWarning(dcAvahi()) << "Service browser client failure:" << d_ptr->client->errorString(); + } +} + +void QtAvahiServiceBrowser::createServiceBrowser(const char *serviceType) +{ + // create a new service browser for the given serviceType + AvahiServiceBrowser *browser = avahi_service_browser_new(d_ptr->client->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, serviceType, NULL, (AvahiLookupFlags) 0, QtAvahiServiceBrowserPrivate::callbackServiceBrowser, this); + d_ptr->serviceBrowserTable.insert(serviceType, browser); +} + diff --git a/libguh/network/avahi/qtavahiservicebrowser.h b/libguh/network/avahi/qtavahiservicebrowser.h new file mode 100644 index 00000000..f2bece2a --- /dev/null +++ b/libguh/network/avahi/qtavahiservicebrowser.h @@ -0,0 +1,62 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef QTAVAHISERVICEBROWSER_H +#define QTAVAHISERVICEBROWSER_H + +#include +#include + +#include "libguh.h" +#include "qtavahiclient.h" +#include "avahiserviceentry.h" + +class QtAvahiServiceBrowserPrivate; + +class LIBGUH_EXPORT QtAvahiServiceBrowser : public QObject +{ + Q_OBJECT +public: + explicit QtAvahiServiceBrowser(QObject *parent = 0); + ~QtAvahiServiceBrowser(); + + void enable(); + + QList serviceEntries() const; + +signals: + void serviceEntryAdded(const AvahiServiceEntry &entry); + void serviceEntryRemoved(const AvahiServiceEntry &entry); + +private slots: + void onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state); + +private: + QtAvahiServiceBrowserPrivate *d_ptr; + + QList m_serviceEntries; + QStringList m_serviceTypes; + + void createServiceBrowser(const char* serviceType); + + Q_DECLARE_PRIVATE(QtAvahiServiceBrowser) +}; + +#endif // QTAVAHISERVICEBROWSER_H diff --git a/libguh/network/avahi/qtavahiservicebrowser_p.cpp b/libguh/network/avahi/qtavahiservicebrowser_p.cpp new file mode 100644 index 00000000..248df381 --- /dev/null +++ b/libguh/network/avahi/qtavahiservicebrowser_p.cpp @@ -0,0 +1,205 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "qtavahiservicebrowser_p.h" +#include "qtavahiservicebrowser.h" +#include "avahiserviceentry.h" +#include "loggingcategories.h" + +#include +#include + +QtAvahiServiceBrowserPrivate::QtAvahiServiceBrowserPrivate(QtAvahiClient *client) : + client(client), + serviceTypeBrowser(NULL) +{ + +} + +void QtAvahiServiceBrowserPrivate::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) + + QtAvahiServiceBrowser *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(dcAvahi()) << "Create service type browser for" << 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->client))); + break; + } +} + +void QtAvahiServiceBrowserPrivate::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); + + QtAvahiServiceBrowser *serviceBrowser = static_cast(userdata); + if (!serviceBrowser) + return; + + switch (event) { + case AVAHI_BROWSER_NEW: + // Start resolving new service + if (!(avahi_service_resolver_new(serviceBrowser->d_ptr->client->client, + interface, + protocol, + name, + type, + domain, + AVAHI_PROTO_UNSPEC, + (AvahiLookupFlags) 0, + QtAvahiServiceBrowserPrivate::callbackServiceResolver, + serviceBrowser))) { + + qCWarning(dcAvahi()) << "Failed to resolve service" << QString(name) << ":" << avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->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() == QtAvahiServiceBrowserPrivate::converProtocol(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->client))); + break; + } + +} + +void QtAvahiServiceBrowserPrivate::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); + + QtAvahiServiceBrowser *serviceBrowser = static_cast(userdata); + if (!serviceBrowser) + 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 = QtAvahiServiceBrowserPrivate::converProtocol(protocol); + QStringList txtList = QtAvahiServiceBrowserPrivate::converTxtList(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); + } + } + avahi_service_resolver_free(resolver); + +} + +QStringList QtAvahiServiceBrowserPrivate::converTxtList(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 QtAvahiServiceBrowserPrivate::converProtocol(const AvahiProtocol &protocol) +{ + QAbstractSocket::NetworkLayerProtocol networkProtocol; + + 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/libguh/network/avahi/qtavahiservicebrowser_p.h b/libguh/network/avahi/qtavahiservicebrowser_p.h new file mode 100644 index 00000000..cd8efbbc --- /dev/null +++ b/libguh/network/avahi/qtavahiservicebrowser_p.h @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef QTAVAHISERVICEBROWSERPRIVATE_H +#define QTAVAHISERVICEBROWSERPRIVATE_H + +#include +#include +#include + +#include "qtavahiclient.h" +#include "qtavahiservice.h" +#include "libguh.h" + +class LIBGUH_EXPORT QtAvahiServiceBrowserPrivate +{ +public: + QtAvahiServiceBrowserPrivate(QtAvahiClient *client); + + // 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 converTxtList(AvahiStringList *txt); + static QAbstractSocket::NetworkLayerProtocol converProtocol(const AvahiProtocol &protocol); + + QtAvahiClient *client; + AvahiServiceTypeBrowser *serviceTypeBrowser; + QHash serviceBrowserTable; +}; + +#endif // QTAVAHISERVICEBROWSERPRIVATE_H diff --git a/libguh/network/avahi/zconfservice.cpp b/libguh/network/avahi/zconfservice.cpp deleted file mode 100644 index 5ac87541..00000000 --- a/libguh/network/avahi/zconfservice.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of qtzeroconf. (c) 2012 Johannes Hilden - * https://github.com/johanneshilden/qtzeroconf - * - * Modified: (C) 2016 Simon Stürz - * - * qtzeroconf 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. - * - * qtzeroconf 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 qtzeroconf; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include -#include -#include -#include "zconfserviceclient.h" -#include "zconfservice.h" - -class ZConfServicePrivate -{ -public: - ZConfServicePrivate() - : client(0), group(0), error(0) - { - } - - static void callback(AvahiEntryGroup *group, AvahiEntryGroupState state, void *userdata) - { - Q_UNUSED(group); - ZConfService *serviceGroup = static_cast(userdata); - if (serviceGroup) { - switch (state) - { - case AVAHI_ENTRY_GROUP_ESTABLISHED: - emit serviceGroup->entryGroupEstablished(); - qDebug() << ("Service '" % serviceGroup->d_ptr->name % "' successfully establised."); - break; - case AVAHI_ENTRY_GROUP_COLLISION: - emit serviceGroup->entryGroupNameCollision(); - break; - case AVAHI_ENTRY_GROUP_FAILURE: - emit serviceGroup->entryGroupFailure(); - qDebug() << ("Entry group failure: " % serviceGroup->errorString()); - break; - case AVAHI_ENTRY_GROUP_UNCOMMITED: - qDebug() << "AVAHI_ENTRY_GROUP_UNCOMMITED"; - break; - case AVAHI_ENTRY_GROUP_REGISTERING: - qDebug() << "AVAHI_ENTRY_GROUP_REGISTERING"; - } // end switch - } - } - - ZConfServiceClient *client; - AvahiEntryGroup *group; - QString name; - in_port_t port; - QString type; - int error; -}; - -/*! - \class ZConfService - - \ingroup hardware - \inmodule libguh - - \brief This class provides Avahi Zeroconf service registration. It can be - used by server applications to announce a service on the local area network. - - Typical use involves creating an instance of ZConfService and calling - registerService() with a service name and port number. -*/ - - -/*! \fn void ZConfService::entryGroupEstablished(); - This signal will be emited when the service entry could be established successfully. -*/ - -/*! \fn void ZConfService::entryGroupNameCollision(); - This signal will be emited when the service entry name collided with an other service. -*/ - -/*! \fn void ZConfService::entryGroupFailure(); - This signal will be emited when the service entry could not be established successfully. -*/ - -/*! Constructs a \l{ZConfService} with the given \a parent.*/ -ZConfService::ZConfService(QObject *parent) - : QObject(parent), - d_ptr(new ZConfServicePrivate) -{ - d_ptr->client = new ZConfServiceClient(this); - d_ptr->client->run(); -} - -/*! Destroys the object and releases all resources associated with it. */ -ZConfService::~ZConfService() -{ - if (d_ptr->group) - avahi_entry_group_free(d_ptr->group); - delete d_ptr; -} - -/*! Returns true if the service group was added and commited without error. */ -bool ZConfService::isValid() const -{ - return (d_ptr->group && !d_ptr->error); -} - -/*! Returns a human readable error string with details of the last error that occured. */ -QString ZConfService::errorString() const -{ - if (!d_ptr->client->client) - return "No client!"; - return avahi_strerror(avahi_client_errno(d_ptr->client->client)); -} - -/*! - Registers a Zeroconf service with the given \a name and \a port on the LAN. If no service \a type is specified, - "_http._tcp" is assumed. - */ -void ZConfService::registerService(QString name, in_port_t port, QString type) -{ - if (!d_ptr->client->client || AVAHI_CLIENT_S_RUNNING - != avahi_client_get_state(d_ptr->client->client)) { - qDebug() << "ZConfService error: Client is not running."; - return; - } - - d_ptr->name = name; - d_ptr->port = port; - d_ptr->type = type; - - if (!d_ptr->group) { - d_ptr->group = avahi_entry_group_new(d_ptr->client->client, - ZConfServicePrivate::callback, - this); - } - - if (avahi_entry_group_is_empty(d_ptr->group)) { - d_ptr->error = avahi_entry_group_add_service(d_ptr->group, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - (AvahiPublishFlags) 0, - d_ptr->name.toLatin1().data(), - d_ptr->type.toLatin1().data(), - 0, - 0, - d_ptr->port, - NULL); - if (!d_ptr->error) { - d_ptr->error = avahi_entry_group_commit(d_ptr->group); - } - if (d_ptr->error) - qDebug() << ("Error creating service: " % errorString()); - } -} - -/*! - Deregisters the service associated with this object. You can reuse the same - ZConfService object at any time to register another service on the network. - */ -void ZConfService::resetService() -{ - avahi_entry_group_reset(d_ptr->group); -} diff --git a/libguh/network/avahi/zconfservice.h b/libguh/network/avahi/zconfservice.h deleted file mode 100644 index 876674f3..00000000 --- a/libguh/network/avahi/zconfservice.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of qtzeroconf. (c) 2012 Johannes Hilden - * https://github.com/johanneshilden/qtzeroconf - * - * Modified: (C) 2016 Simon Stürz - * - * qtzeroconf 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. - * - * qtzeroconf 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 qtzeroconf; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef ZCONFSERVICE_H -#define ZCONFSERVICE_H - -#include -#include - -class ZConfServicePrivate; -class ZConfService : public QObject -{ - Q_OBJECT - -public: - explicit ZConfService(QObject *parent = 0); - ~ZConfService(); - - bool isValid() const; - QString errorString() const; - -public slots: - void registerService(QString name, in_port_t port, QString type = "_http._tcp"); - void resetService(); - -protected: - ZConfServicePrivate *const d_ptr; - -private: - Q_DECLARE_PRIVATE(ZConfService) - -signals: - void entryGroupEstablished(); - void entryGroupNameCollision(); - void entryGroupFailure(); - -}; - -#endif // ZCONFSERVICE_H diff --git a/libguh/network/avahi/zconfservicebrowser.cpp b/libguh/network/avahi/zconfservicebrowser.cpp deleted file mode 100644 index 9eb43d70..00000000 --- a/libguh/network/avahi/zconfservicebrowser.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * This file is part of qtzeroconf. (c) 2012 Johannes Hilden - * https://github.com/johanneshilden/qtzeroconf - * - * Modified: (C) 2016 Simon Stürz - * - * qtzeroconf 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. - * - * qtzeroconf 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 qtzeroconf; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include -#include - -#include "zconfservicebrowser.h" -#include "zconfserviceclient.h" - -class ZConfServiceBrowserPrivate -{ -public: - ZConfServiceBrowserPrivate(ZConfServiceClient *client) - : client(client), browser(0) - { - } - - static void callback(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); - - ZConfServiceBrowser *serviceBrowser = static_cast(userdata); - if (serviceBrowser) { - switch (event) { - case AVAHI_BROWSER_FAILURE: - qDebug() << ("Avahi browser error: " % QString(avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->client)))); - emit serviceBrowser->serviceBrowsingFinished(); - break; - case AVAHI_BROWSER_NEW: - qDebug() << ("New service '" % QString(name) % "' of type " % QString(type) % " in domain " % QString(domain) % "."); - - // We ignore the returned resolver object. In the callback - // function we free it. If the server is terminated before - // the callback function is called the server will free - // the resolver for us. - if (!(avahi_service_resolver_new(serviceBrowser->d_ptr->client->client, - interface, - protocol, - name, - serviceBrowser->d_ptr->type.toLatin1().data(), - domain, - AVAHI_PROTO_UNSPEC, - (AvahiLookupFlags) 0, - ZConfServiceBrowserPrivate::resolve, - serviceBrowser))) - qDebug() << ("Failed to resolve service '" % QString(name) % "': " % avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->client))); - break; - case AVAHI_BROWSER_REMOVE: - serviceBrowser->d_ptr->entries.remove(name); - emit serviceBrowser->serviceEntryRemoved(name); - break; - case AVAHI_BROWSER_ALL_FOR_NOW: - emit serviceBrowser->serviceBrowsingFinished(); - break; - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - } - } - } - - static void resolve(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); - - ZConfServiceBrowser *serviceBrowser = static_cast(userdata); - if (serviceBrowser) { - switch (event) { - case AVAHI_RESOLVER_FAILURE: - qDebug() << ("Failed to resolve service '" % QString(name) % "': " % avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->client))); - break; - case AVAHI_RESOLVER_FOUND: - { - char a[AVAHI_ADDRESS_STR_MAX]; - avahi_address_snprint(a, sizeof(a), address); - - // convert protocol - QAbstractSocket::NetworkLayerProtocol p; - if (protocol == AVAHI_PROTO_INET) { - p = QAbstractSocket::IPv4Protocol; - } else if (protocol == AVAHI_PROTO_INET6) { - p = QAbstractSocket::IPv6Protocol; - } else { - p = QAbstractSocket::UnknownNetworkLayerProtocol; - } - - QStringList txtList; - // TODO: get txt string list - // // get txt string list - // if (txt) { - // AvahiStringList *txtAtt = txt->text; - // txtAtt = (txt ? txt->next : 0); - // while (txtAtt) { - // qDebug() << txt; - // txtList.append(QString(txt->)); - // } - // } - - AvahiServiceEntry entry = AvahiServiceEntry(name, QHostAddress(QString(a)), QString(domain), QString(host_name), (quint16)port, p, txtList, flags); - - serviceBrowser->d_ptr->entries.insert(name, entry); - emit serviceBrowser->serviceEntryAdded(name); - } - } - avahi_service_resolver_free(resolver); - } - } - - typedef QHash ZConfServiceEntryTable; - - ZConfServiceClient *const client; - AvahiServiceBrowser *browser; - ZConfServiceEntryTable entries; - QString type; -}; - -/*! - \class ZConfServiceBrowser - - \ingroup hardware - \inmodule libguh - - \brief AvahiServiceBrowser wrapper that lets you browse for services - available on the local network. This class can be used to handle Zeroconf - service discovery in a Qt-based client application. - - Instantiate a ZConfServiceBrowser object and call browse() with the desired - service type as argument (e.g., "_http._tcp" or "_ipp._tcp"). - - ZConfServiceBrowser will emit serviceEntryAdded() when a new service is - discovered and serviceEntryRemoved() when a service is removed from the - network. -*/ - -/*! \fn void ZConfServiceBrowser::serviceEntryAdded(const QString &name); - This signal will be emited when a new service entry with the given \a name was added in the network. -*/ - -/*! \fn void ZConfServiceBrowser::serviceEntryRemoved(const QString &name); - This signal will be emited when a new service entry with the given \a name was removed from the network. -*/ - -/*! Creates a Zeroconf service browser with the given \a parent. Call browse() to start browsing for services. */ -ZConfServiceBrowser::ZConfServiceBrowser(QObject *parent) - : QObject(parent), - d_ptr(new ZConfServiceBrowserPrivate(new ZConfServiceClient(this))) -{ - connect(d_ptr->client, SIGNAL(clientRunning()), this, SLOT(createServiceBrowser())); -} - -/*! Destroys the browser object and releases all resources associated with it. */ -ZConfServiceBrowser::~ZConfServiceBrowser() -{ - if (d_ptr->browser) - avahi_service_browser_free(d_ptr->browser); - delete d_ptr; -} - -/*! - Browses for Zeroconf services of the given \a serviceType on the LAN. This is a non-blocking call. - ZConfServiceBrowser will emit serviceEntryAdded() when a new service is - discovered and serviceEntryRemoved() when a service is removed from the - network. - */ -void ZConfServiceBrowser::browse(QString serviceType) -{ - d_ptr->type = serviceType; - if(d_ptr->client) - d_ptr->client->run(); -} - -/*! - Returns a ZConfServiceEntry struct with detailed information about the - Zeroconf service associated with the \a name. - */ -AvahiServiceEntry ZConfServiceBrowser::serviceEntry(QString name) -{ - return d_ptr->entries.value(name); -} - -void ZConfServiceBrowser::createServiceBrowser() -{ - if (d_ptr->browser) - return; - d_ptr->browser = avahi_service_browser_new(d_ptr->client->client, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - d_ptr->type.toLatin1().data(), - NULL, - (AvahiLookupFlags) 0, - ZConfServiceBrowserPrivate::callback, - this); -} diff --git a/libguh/network/avahi/zconfservicebrowser.h b/libguh/network/avahi/zconfservicebrowser.h deleted file mode 100644 index 3859a84b..00000000 --- a/libguh/network/avahi/zconfservicebrowser.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of qtzeroconf. (c) 2012 Johannes Hilden - * https://github.com/johanneshilden/qtzeroconf - * - * Modified: (C) 2016 Simon Stürz - * - * qtzeroconf 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. - * - * qtzeroconf 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 qtzeroconf; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef ZCONFSERVICEBROWSER_H -#define ZCONFSERVICEBROWSER_H - -#include -#include -#include - -#include "avahiserviceentry.h" - -class ZConfServiceBrowserPrivate; -class ZConfServiceBrowser : public QObject -{ - Q_OBJECT - -public: - explicit ZConfServiceBrowser(QObject *parent = 0); - ~ZConfServiceBrowser(); - - void browse(QString serviceType = "_http._tcp"); - AvahiServiceEntry serviceEntry(QString name); - -signals: - void serviceEntryAdded(const QString &name); - void serviceEntryRemoved(const QString &name); - void serviceBrowsingFinished(); - -private slots: - void createServiceBrowser(); - -protected: - ZConfServiceBrowserPrivate *const d_ptr; - -private: - Q_DECLARE_PRIVATE(ZConfServiceBrowser) -}; - -#endif // ZCONFSERVICEBROWSER_H diff --git a/libguh/network/avahi/zconfserviceclient.cpp b/libguh/network/avahi/zconfserviceclient.cpp deleted file mode 100644 index 1be1bcbe..00000000 --- a/libguh/network/avahi/zconfserviceclient.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of qtzeroconf. (c) 2012 Johannes Hilden - * https://github.com/johanneshilden/qtzeroconf - * - * Modified: (C) 2016 Simon Stürz - * - * qtzeroconf 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. - * - * qtzeroconf 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 qtzeroconf; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include "zconfserviceclient.h" -#include "qt-watch.h" - -void ZConfServiceClient::run() -{ - if (client) - return; - avahi_client_new(poll, (AvahiClientFlags) 0, ZConfServiceClient::callback, this, &error); -} - -QString ZConfServiceClient::errorString() const -{ - return avahi_strerror(error); -} - -ZConfServiceClient::ZConfServiceClient(QObject *parent) - : QObject(parent), - poll(avahi_qt_poll_get()), - client(0), - error(0) -{ -} - -ZConfServiceClient::~ZConfServiceClient() -{ - if (client) - // This will automatically free all associated browser, - // resolve and entry group objects. - avahi_client_free(client); -} - -void ZConfServiceClient::callback(AvahiClient *client, AvahiClientState state, void *userdata) -{ - ZConfServiceClient *service = static_cast(userdata); - if (service) { - service->client = client; - switch (state) - { - case AVAHI_CLIENT_S_RUNNING: - qDebug() << "AVAHI_CLIENT_S_RUNNING"; - // The server has started up successfully and registered its host - // name on the network. - emit service->clientRunning(); - break; - case AVAHI_CLIENT_FAILURE: - qDebug() << "AVAHI_CLIENT_FAILURE"; - emit service->clientFailure(); - break; - case AVAHI_CLIENT_S_COLLISION: - case AVAHI_CLIENT_S_REGISTERING: - qDebug() << (AVAHI_CLIENT_S_COLLISION == state - ? "AVAHI_CLIENT_S_COLLISION" - : "AVAHI_CLIENT_S_REGISTERING"); - emit service->clientReset(); - break; - case AVAHI_CLIENT_CONNECTING: - qDebug() << "AVAHI_CLIENT_CONNECTING"; - emit service->clientConnecting(); - } // end switch - } -} diff --git a/libguh/network/avahi/zconfserviceclient.h b/libguh/network/avahi/zconfserviceclient.h deleted file mode 100644 index 21569569..00000000 --- a/libguh/network/avahi/zconfserviceclient.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of qtzeroconf. (c) 2012 Johannes Hilden - * https://github.com/johanneshilden/qtzeroconf - * - * Modified: (C) 2016 Simon Stürz - * - * qtzeroconf 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. - * - * qtzeroconf 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 qtzeroconf; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef ZCONFSERVICECLIENT_H -#define ZCONFSERVICECLIENT_H - -#include -#include - -class ZConfServiceClient : public QObject -{ - Q_OBJECT - -signals: - void clientRunning(); - void clientFailure(); - void clientConnecting(); - void clientReset(); - -private: - friend class ZConfService; - friend class ZConfServiceBrowser; - friend class ZConfServiceBrowserPrivate; - - ZConfServiceClient(QObject *parent = 0); - ~ZConfServiceClient(); - - void run(); - QString errorString() const; - - static void callback(AvahiClient *client, AvahiClientState state, void *userdata); - - const AvahiPoll *const poll; - AvahiClient *client; - int error; -}; - -#endif // ZCONFSERVICECLIENT_H diff --git a/libguh/plugin/deviceplugin.cpp b/libguh/plugin/deviceplugin.cpp index ec1b87a8..86971486 100644 --- a/libguh/plugin/deviceplugin.cpp +++ b/libguh/plugin/deviceplugin.cpp @@ -681,14 +681,24 @@ void DevicePlugin::upnpDiscover(QString searchTarget, QString userAgent) { if(requiredHardware().testFlag(DeviceManager::HardwareResourceUpnpDisovery)){ deviceManager()->m_upnpDiscovery->discoverDevices(searchTarget, userAgent, pluginId()); + } else { + qCWarning(dcDeviceManager) << "UPnP discovery resource not set for plugin" << pluginName(); } } +/*! Returns the pointer to the central \l{QtAvahiService}{service} browser. */ +QtAvahiServiceBrowser *DevicePlugin::avahiServiceBrowser() const +{ + return deviceManager()->m_avahiBrowser; +} + #ifdef BLUETOOTH_LE bool DevicePlugin::discoverBluetooth() { if(requiredHardware().testFlag(DeviceManager::HardwareResourceBluetoothLE)){ return deviceManager()->m_bluetoothScanner->discover(pluginId()); + } else { + qCWarning(dcDeviceManager) << "Bluetooth LE resource not set for plugin" << pluginName(); } return false; } diff --git a/libguh/plugin/deviceplugin.h b/libguh/plugin/deviceplugin.h index 927b6ff1..72a1734c 100644 --- a/libguh/plugin/deviceplugin.h +++ b/libguh/plugin/deviceplugin.h @@ -76,15 +76,16 @@ public: // Hardware input virtual void radioData(const QList &rawData) {Q_UNUSED(rawData)} virtual void guhTimer() {} - virtual void upnpDiscoveryFinished(const QList &upnpDeviceDescriptorList) {Q_UNUSED(upnpDeviceDescriptorList)} + virtual void upnpDiscoveryFinished(const QList &upnpDeviceDescriptorList) { Q_UNUSED(upnpDeviceDescriptorList) } virtual void upnpNotifyReceived(const QByteArray ¬ifyData) {Q_UNUSED(notifyData)} virtual void networkManagerReplyReady(QNetworkReply *reply) {Q_UNUSED(reply)} #ifdef BLUETOOTH_LE - virtual void bluetoothDiscoveryFinished(const QList &deviceInfos) {Q_UNUSED(deviceInfos)} + virtual void bluetoothDiscoveryFinished(const QList &deviceInfos) { Q_UNUSED(deviceInfos) } #endif + // Configuration QList configurationDescription() const; DeviceManager::DeviceError setConfiguration(const ParamList &configuration); @@ -109,6 +110,9 @@ protected: // Radio 433 bool transmitData(int delay, QList rawData); + // Avahi browse services + QtAvahiServiceBrowser *avahiServiceBrowser() const; + // Bluetooth LE discovery #ifdef BLUETOOTH_LE bool discoverBluetooth(); diff --git a/plugins/deviceplugins/avahimonitor/avahimonitor.pro b/plugins/deviceplugins/avahimonitor/avahimonitor.pro new file mode 100644 index 00000000..b8e9b64e --- /dev/null +++ b/plugins/deviceplugins/avahimonitor/avahimonitor.pro @@ -0,0 +1,11 @@ +include(../../plugins.pri) + +TARGET = $$qtLibraryTarget(guh_devicepluginavahimonitor) + +SOURCES += \ + devicepluginavahimonitor.cpp + +HEADERS += \ + devicepluginavahimonitor.h + + diff --git a/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.cpp b/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.cpp new file mode 100644 index 00000000..bbb68ef3 --- /dev/null +++ b/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.cpp @@ -0,0 +1,99 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2014 Michael Zanetti * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*! + \page wifidetector.html + \title WiFi Detector + \brief Plugin to monitor devices in the local network. + + \ingroup plugins + \ingroup guh-plugins + + This plugin allows to find and monitor network devices in your local network by using the MAC address. + + \underline{NOTE}: the application \c nmap has to be installed and guh has to run as root. + + \chapter Plugin properties + Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses} + and \l{Vendor}{Vendors} of this \l{DevicePlugin}. + + For more details how to read this JSON file please check out the documentation for \l{The plugin JSON File}. + + \quotefile plugins/deviceplugins/wifidetector/devicepluginwifidetector.json +*/ + + +#include "devicepluginavahimonitor.h" + +#include "plugin/device.h" +#include "devicemanager.h" +#include "plugininfo.h" + +#include +#include +#include + +DevicePluginAvahiMonitor::DevicePluginAvahiMonitor() +{ +} + +DeviceManager::DeviceSetupStatus DevicePluginAvahiMonitor::setupDevice(Device *device) +{ + qCDebug(dcAvahiMonitor()) << "Setup" << device->name() << device->params(); + + connect(avahiServiceBrowser(), SIGNAL(serviceEntryAdded(AvahiServiceEntry)), this, SLOT(onServiceEntryAdded(AvahiServiceEntry))); + connect(avahiServiceBrowser(), SIGNAL(serviceEntryRemoved(AvahiServiceEntry)), this, SLOT(onServiceEntryRemoved(AvahiServiceEntry))); + + return DeviceManager::DeviceSetupStatusSuccess; +} + +DeviceManager::DeviceError DevicePluginAvahiMonitor::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) +{ + Q_UNUSED(params) + + if (deviceClassId != avahiDeviceClassId) + return DeviceManager::DeviceErrorDeviceClassNotFound; + + QList deviceDescriptors; + foreach (const AvahiServiceEntry &service, avahiServiceBrowser()->serviceEntries()) { + DeviceDescriptor deviceDescriptor(avahiDeviceClassId, service.name(), service.hostAddress().toString()); + deviceDescriptors.append(deviceDescriptor); + } + + emit devicesDiscovered(avahiDeviceClassId, deviceDescriptors); + + return DeviceManager::DeviceErrorAsync; +} + +DeviceManager::HardwareResources DevicePluginAvahiMonitor::requiredHardware() const +{ + return DeviceManager::HardwareResourceNone; +} + +void DevicePluginAvahiMonitor::onServiceEntryAdded(const AvahiServiceEntry &serviceEntry) +{ + Q_UNUSED(serviceEntry) +} + +void DevicePluginAvahiMonitor::onServiceEntryRemoved(const AvahiServiceEntry &serviceEntry) +{ + Q_UNUSED(serviceEntry) +} diff --git a/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.h b/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.h new file mode 100644 index 00000000..59779173 --- /dev/null +++ b/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2014 Michael Zanetti * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICEPLUGINAVAHIMONITOR_H +#define DEVICEPLUGINAVAHIMONITOR_H + +#include "plugin/deviceplugin.h" + +#include + +class DevicePluginAvahiMonitor : public DevicePlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "devicepluginavahimonitor.json") + Q_INTERFACES(DevicePlugin) + +public: + explicit DevicePluginAvahiMonitor(); + + DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; + DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; + DeviceManager::HardwareResources requiredHardware() const override; + +private slots: + void onServiceEntryAdded(const AvahiServiceEntry &serviceEntry); + void onServiceEntryRemoved(const AvahiServiceEntry &serviceEntry); +}; + +#endif // DEVICEPLUGINAVAHIMONITOR_H diff --git a/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.json b/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.json new file mode 100644 index 00000000..ba65bf44 --- /dev/null +++ b/plugins/deviceplugins/avahimonitor/devicepluginavahimonitor.json @@ -0,0 +1,32 @@ +{ + "name": "Avahi Monitor", + "idName": "AvahiMonitor", + "id": "d83fb167-cef7-4347-8c58-fa39df7bea4f", + "vendors": [ + { + "name": "guh", + "idName": "guh", + "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", + "deviceClasses": [ + { + "deviceClassId": "97f0154d-6945-49b8-bd65-0a8cea0c6652", + "name": "Avahi Monitor", + "idName": "avahi", + "deviceIcon": "Network", + "basicTags": [ + "Device", + "Sensor" + ], + "createMethods": ["discovery"], + "paramTypes": [ + { + "name": "name", + "type": "QString", + "inputType": "TextLine" + } + ] + } + ] + } + ] +} diff --git a/plugins/deviceplugins/deviceplugins.pro b/plugins/deviceplugins/deviceplugins.pro index df065012..0a452e8e 100644 --- a/plugins/deviceplugins/deviceplugins.pro +++ b/plugins/deviceplugins/deviceplugins.pro @@ -26,3 +26,5 @@ SUBDIRS += elro \ ws2812 \ orderbutton \ denon \ + avahimonitor \ + diff --git a/server/main.cpp b/server/main.cpp index 68e53745..b6179869 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -118,6 +118,8 @@ int main(int argc, char *argv[]) s_loggingFilters.insert("Rest", false); s_loggingFilters.insert("OAuth2", false); s_loggingFilters.insert("TimeManager", false); + s_loggingFilters.insert("Coap", false); + s_loggingFilters.insert("Avahi", false); QHash loggingFiltersPlugins; foreach (const QJsonObject &pluginMetadata, DeviceManager::pluginsMetadata()) { diff --git a/server/webserver.cpp b/server/webserver.cpp index dbbdab88..6ddfe260 100644 --- a/server/webserver.cpp +++ b/server/webserver.cpp @@ -129,11 +129,9 @@ WebServer::WebServer(const QSslConfiguration &sslConfiguration, QObject *parent) // Create avahi service #ifndef TESTING_ENABLED - m_avahiService = new ZConfService(this); - connect(m_avahiService, SIGNAL(entryGroupEstablished()), this, SLOT(onEntryGroupEstablished())); - connect(m_avahiService, SIGNAL(entryGroupFailure()), this, SLOT(onEntryGroupEstablished())); - connect(m_avahiService, SIGNAL(entryGroupNameCollision()), this, SLOT(onEntryGroupEstablished())); - m_avahiService->registerService("guhd", m_port); + m_avahiService = new QtAvahiService(this); + connect(m_avahiService, &QtAvahiService::serviceStateChanged, this, &WebServer::onAvahiServiceStateChanged); + m_avahiService->registerService("guhIO", m_port); #endif } @@ -142,9 +140,6 @@ WebServer::~WebServer() { qCDebug(dcApplication) << "Shutting down \"Webserver\""; this->close(); - qCDebug(dcApplication) << "Shutting down \"Avahi Service\""; - if (m_avahiService) - m_avahiService->resetService(); } /*! Send the given \a reply map to the corresponding client. @@ -538,19 +533,11 @@ void WebServer::onError(QAbstractSocket::SocketError error) qCWarning(dcConnection) << QString("Client socket error %1:%2 ->").arg(socket->peerAddress().toString()).arg(socket->peerPort()) << socket->errorString(); } -void WebServer::onEntryGroupEstablished() +void WebServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state) { - qCDebug(dcWebServer()) << "Avahi webserver service established successfully."; -} - -void WebServer::onEntryGroupFailure() -{ - qCWarning(dcWebServer()) << "Avahi webserver service establishment failed."; -} - -void WebServer::onEntryGroupNameCollision() -{ - qCWarning(dcWebServer()) << "Avahi webserver service establishment failed. Name collision."; + if (state == QtAvahiService::QtAvahiServiceStateEstablished) { + qCDebug(dcAvahi()) << "Service" << m_avahiService->name() << "established successfully"; + } } /*! Returns true if this \l{WebServer} started successfully. */ diff --git a/server/webserver.h b/server/webserver.h index 814d05e3..b12c9290 100644 --- a/server/webserver.h +++ b/server/webserver.h @@ -34,7 +34,7 @@ #include #include -#include "network/avahi/zconfservice.h" +#include "network/avahi/qtavahiservice.h" // Note: Hypertext Transfer Protocol (HTTP/1.1) from the Internet Engineering Task Force (IETF): // https://tools.ietf.org/html/rfc7231 @@ -65,7 +65,6 @@ private: private slots: void onTimout(); - }; @@ -86,7 +85,7 @@ private: QList m_webServerClients; QHash m_incompleteRequests; - ZConfService *m_avahiService; + QtAvahiService *m_avahiService; QSslConfiguration m_sslConfiguration; bool m_useSsl; @@ -116,10 +115,7 @@ private slots: void onEncrypted(); void onError(QAbstractSocket::SocketError error); - // avahi service - void onEntryGroupEstablished(); - void onEntryGroupFailure(); - void onEntryGroupNameCollision(); + void onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state); public slots: