add avahi lib

pull/135/head
Simon Stürz 2016-04-28 14:06:54 +02:00 committed by Michael Zanetti
parent 5bfc85200c
commit f04ac4cac6
25 changed files with 1107 additions and 16 deletions

11
debian/control vendored
View File

@ -7,8 +7,11 @@ Build-Depends: debhelper (>= 9.0.0),
hardening-wrapper,
python,
qt5-default,
qtbase5-dev
Standards-Version: 3.9.3
qtbase5-dev,
qtconnectivity5-dev,
libavahi-client-dev,
libavahi-common-dev
Standards-Version: 3.9.5
Package: guh
Architecture: any
@ -83,7 +86,9 @@ Section: libs
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
libqt5bluetooth5
libqt5bluetooth5,
libavahi-client3,
libavahi-common3
Description: An open source IoT server - core library
guh is an open source IoT (Internet of Things) server,
which allows to control a lot of different devices from many different

13
debian/copyright vendored
View File

@ -16,3 +16,16 @@ Files: debian/*
Copyright: (C) 2014 Michael Zanetti <michael_zanetti@gmx.net>
2014 Simon Stürz <stuerz.simon@gmail.com>
License: GPL-2+
Files: libguh/avahi/zconf*
Copyright: (c) 2012 Johannes Hilden
2016 Simon Stürz <stuerz.simon@gmail.com>
License: LGPL-2.1
Files: libguh/avahi/qt-watch*
Copyright: (c) avahi
2016 Simon Stürz <stuerz.simon@gmail.com>
License: LGPL-2.1

View File

@ -83,7 +83,7 @@ Coap::Coap(QObject *parent, const quint16 &port) :
{
m_socket = new QUdpSocket(this);
if (!m_socket->bind(QHostAddress::Any, port))
if (!m_socket->bind(QHostAddress::Any, port, QAbstractSocket::ShareAddress))
qCWarning(dcCoap) << "Could not bind to port" << port << m_socket->errorString();
connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));

View File

@ -33,6 +33,8 @@
#include "types/vendor.h"
#include "network/networkmanager.h"
#include "network/upnp/upnpdiscovery.h"
#include "network/upnp/upnpdevicedescriptor.h"
#ifdef BLUETOOTH_LE
#include "bluetooth/bluetoothscanner.h"

View File

@ -11,6 +11,10 @@ QMAKE_LFLAGS += -fPIC
target.path = /usr/lib
INSTALLS += target
# Avahi libs
LIBS += -lavahi-common -lavahi-client
# check Bluetooth LE support
contains(DEFINES, BLUETOOTH_LE) {
HEADERS += bluetooth/bluetoothscanner.h \
bluetooth/bluetoothlowenergydevice.h \
@ -32,15 +36,21 @@ HEADERS += devicemanager.h \
plugin/devicepairinginfo.h \
hardware/gpio.h \
hardware/gpiomonitor.h \
hardware/pwm.h \
hardware/radio433/radio433.h \
hardware/radio433/radio433transmitter.h \
hardware/radio433/radio433brennenstuhlgateway.h \
network/upnpdiscovery/upnpdiscovery.h \
network/upnpdiscovery/upnpdevice.h \
network/upnpdiscovery/upnpdevicedescriptor.h \
network/upnpdiscovery/upnpdiscoveryrequest.h \
network/upnp/upnpdiscovery.h \
network/upnp/upnpdevice.h \
network/upnp/upnpdevicedescriptor.h \
network/upnp/upnpdiscoveryrequest.h \
network/networkmanager.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 \
coap/coap.h \
coap/coappdu.h \
coap/coapoption.h \
@ -64,7 +74,6 @@ HEADERS += devicemanager.h \
types/ruleaction.h \
types/ruleactionparam.h \
types/statedescriptor.h \
hardware/pwm.h
SOURCES += devicemanager.cpp \
@ -77,15 +86,21 @@ SOURCES += devicemanager.cpp \
plugin/devicepairinginfo.cpp \
hardware/gpio.cpp \
hardware/gpiomonitor.cpp \
hardware/pwm.cpp \
hardware/radio433/radio433.cpp \
hardware/radio433/radio433transmitter.cpp \
hardware/radio433/radio433brennenstuhlgateway.cpp \
network/upnpdiscovery/upnpdiscovery.cpp \
network/upnpdiscovery/upnpdevice.cpp \
network/upnpdiscovery/upnpdevicedescriptor.cpp \
network/upnpdiscovery/upnpdiscoveryrequest.cpp \
network/upnp/upnpdiscovery.cpp \
network/upnp/upnpdevice.cpp \
network/upnp/upnpdevicedescriptor.cpp \
network/upnp/upnpdiscoveryrequest.cpp \
network/networkmanager.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 \
coap/coap.cpp \
coap/coappdu.cpp \
coap/coapoption.cpp \
@ -109,7 +124,6 @@ SOURCES += devicemanager.cpp \
types/ruleaction.cpp \
types/ruleactionparam.cpp \
types/statedescriptor.cpp \
hardware/pwm.cpp
# install plugininfo python script for libguh-dev

View File

@ -0,0 +1,113 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2016 Simon Stürz <simon.stuerz@guh.guru> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "avahiserviceentry.h"
AvahiServiceEntry::AvahiServiceEntry() :
m_port(0),
m_protocol(QAbstractSocket::UnknownNetworkLayerProtocol)
{
}
AvahiServiceEntry::AvahiServiceEntry(QString name, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags) :
m_name(name),
m_hostAddress(hostAddress),
m_domain(domain),
m_hostName(hostName),
m_port(port),
m_protocol(protocol),
m_txt(txt),
m_flags(flags)
{
}
QString AvahiServiceEntry::name() const
{
return m_name;
}
QHostAddress AvahiServiceEntry::hostAddress() const
{
return m_hostAddress;
}
QString AvahiServiceEntry::domain() const
{
return m_domain;
}
QString AvahiServiceEntry::hostName() const
{
return m_hostName;
}
quint16 AvahiServiceEntry::port() const
{
return m_port;
}
QAbstractSocket::NetworkLayerProtocol AvahiServiceEntry::protocol() const
{
return m_protocol;
}
AvahiLookupResultFlags AvahiServiceEntry::flags() const
{
return m_flags;
}
QStringList AvahiServiceEntry::txt() const
{
return m_txt;
}
bool AvahiServiceEntry::isValid() const
{
return !m_hostAddress.isNull() && !m_hostName.isEmpty() && m_port != 0 && m_protocol != QAbstractSocket::UnknownNetworkLayerProtocol;
}
bool AvahiServiceEntry::isChached() const
{
return m_flags & AVAHI_LOOKUP_RESULT_CACHED;
}
bool AvahiServiceEntry::isWideArea() const
{
return m_flags & AVAHI_LOOKUP_RESULT_WIDE_AREA;
}
bool AvahiServiceEntry::isMulticast() const
{
return m_flags & AVAHI_LOOKUP_RESULT_MULTICAST;
}
bool AvahiServiceEntry::isLocal() const
{
return m_flags & AVAHI_LOOKUP_RESULT_LOCAL;
}
bool AvahiServiceEntry::isOurOwn() const
{
return m_flags & AVAHI_LOOKUP_RESULT_OUR_OWN;
}

View File

@ -0,0 +1,64 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2016 Simon Stürz <simon.stuerz@guh.guru> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef AVAHISERVICEENTRY_H
#define AVAHISERVICEENTRY_H
#include <QObject>
#include <QString>
#include <QHostAddress>
#include <avahi-client/publish.h>
class AvahiServiceEntry
{
public:
AvahiServiceEntry();
AvahiServiceEntry(QString name, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags);
QString name() 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;
bool isChached() const;
bool isWideArea() const;
bool isMulticast() const;
bool isLocal() const;
bool isOurOwn() const;
private:
QString m_name;
QHostAddress m_hostAddress;
QString m_domain;
QString m_hostName;
quint16 m_port;
QAbstractSocket::NetworkLayerProtocol m_protocol;
QStringList m_txt;
AvahiLookupResultFlags m_flags;
};
#endif // AVAHISERVICEENTRY_H

View File

@ -0,0 +1,193 @@
/***
This file is part of avahi.
Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
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.
***/
#include <QObject>
#include <QTimer>
#include <QSocketNotifier>
#include <sys/time.h>
#include <avahi-common/timeval.h>
#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_IN;
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"

View File

@ -0,0 +1,35 @@
#ifndef QAVAHI_H
#define QAVAHI_H
/***
This file is part of avahi.
Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
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.
***/
/** \file qt-watch.h Qt main loop adapter */
#include <avahi-common/watch.h>
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

View File

@ -0,0 +1,169 @@
/*
* This file is part of qtzeroconf. (c) 2012 Johannes Hilden
* https://github.com/johanneshilden/qtzeroconf
*
* Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
*
* 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 <QDebug>
#include <QStringBuilder>
#include <avahi-client/publish.h>
#include <avahi-common/error.h>
#include <avahi-common/alternative.h>
#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<ZConfService *>(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
\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.
*/
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 on the LAN. If no service type is specified,
"_http._tcp" is assumed. Needless to say, the server should be available
and listen on the specified port.
*/
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);
}

View File

@ -0,0 +1,56 @@
/*
* This file is part of qtzeroconf. (c) 2012 Johannes Hilden
* https://github.com/johanneshilden/qtzeroconf
*
* Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
*
* 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 <QObject>
#include <arpa/inet.h>
class ZConfServicePrivate;
class ZConfService : public QObject
{
Q_OBJECT
public:
explicit ZConfService(QObject *parent = 0);
~ZConfService();
bool isValid() const;
QString errorString() const;
signals:
void entryGroupEstablished();
void entryGroupNameCollision();
void entryGroupFailure();
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)
};
#endif // ZCONFSERVICE_H

View File

@ -0,0 +1,230 @@
/*
* This file is part of qtzeroconf. (c) 2012 Johannes Hilden
* https://github.com/johanneshilden/qtzeroconf
*
* Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
*
* 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 <QHash>
#include <QStringBuilder>
#include <QDebug>
#include <avahi-common/error.h>
#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<ZConfServiceBrowser *>(userdata);
if (serviceBrowser) {
switch (event) {
case AVAHI_BROWSER_FAILURE:
qDebug() << ("Avahi browser error: " % QString(avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->client))));
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);
qDebug() << "Service '" % QString(name) % "' removed from the network.";
break;
case AVAHI_BROWSER_ALL_FOR_NOW:
case AVAHI_BROWSER_CACHE_EXHAUSTED:
qDebug() << (AVAHI_BROWSER_ALL_FOR_NOW == event
? "AVAHI_BROWSER_ALL_FOR_NOW"
: "AVAHI_BROWSER_CACHE_EXHAUSTED");
} // end switch
}
}
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<ZConfServiceBrowser *>(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<QString, AvahiServiceEntry> ZConfServiceEntryTable;
ZConfServiceClient *const client;
AvahiServiceBrowser *browser;
ZConfServiceEntryTable entries;
QString type;
};
/*!
\class ZConfServiceBrowser
\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.
*/
/*!
Creates a Zeroconf service browser. 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 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 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);
}

View File

@ -0,0 +1,57 @@
/*
* This file is part of qtzeroconf. (c) 2012 Johannes Hilden
* https://github.com/johanneshilden/qtzeroconf
*
* Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
*
* 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 <QObject>
#include <stdint-gcc.h>
#include <avahi-client/lookup.h>
#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(QString);
void serviceEntryRemoved(QString);
protected slots:
void createServiceBrowser();
protected:
ZConfServiceBrowserPrivate *const d_ptr;
private:
Q_DECLARE_PRIVATE(ZConfServiceBrowser)
};
#endif // ZCONFSERVICEBROWSER_H

View File

@ -0,0 +1,84 @@
/*
* This file is part of qtzeroconf. (c) 2012 Johannes Hilden
* https://github.com/johanneshilden/qtzeroconf
*
* Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
*
* 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 <QDebug>
#include <avahi-common/error.h>
#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<ZConfServiceClient *>(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
}
}

View File

@ -0,0 +1,56 @@
/*
* This file is part of qtzeroconf. (c) 2012 Johannes Hilden
* https://github.com/johanneshilden/qtzeroconf
*
* Modified: (C) 2016 Simon Stürz <stuerz.simon@gmail.com>
*
* 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 <QObject>
#include <avahi-client/client.h>
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

View File

@ -139,7 +139,7 @@
#include "devicemanager.h"
#include "guhsettings.h"
#include "hardware/radio433/radio433.h"
#include "network/upnpdiscovery/upnpdiscovery.h"
#include "network/upnp/upnpdiscovery.h"
#include <QDebug>
#include <QFileInfo>

View File

@ -23,7 +23,7 @@
#include "plugin/deviceplugin.h"
#include "tvdevice.h"
#include "network/upnpdiscovery/upnpdevicedescriptor.h"
#include "network/upnp/upnpdevicedescriptor.h"
class DevicePluginLgSmartTv : public DevicePlugin
{