summaryrefslogtreecommitdiffstats
path: root/dnssd
diff options
context:
space:
mode:
Diffstat (limited to 'dnssd')
-rw-r--r--dnssd/Makefile.am4
-rw-r--r--dnssd/README7
-rw-r--r--dnssd/configure.in.in49
-rw-r--r--dnssd/domainbrowser.cpp75
-rw-r--r--dnssd/publicservice.cpp192
-rw-r--r--dnssd/publicservice.h5
-rw-r--r--dnssd/query.cpp132
-rw-r--r--dnssd/remoteservice.cpp105
-rw-r--r--dnssd/responder.cpp75
-rw-r--r--dnssd/responder.h34
-rw-r--r--dnssd/sdevent.h9
-rw-r--r--dnssd/servicebase.cpp2
-rw-r--r--dnssd/servicebrowser.cpp25
13 files changed, 391 insertions, 323 deletions
diff --git a/dnssd/Makefile.am b/dnssd/Makefile.am
index 5c9edb9c4..268e72a5d 100644
--- a/dnssd/Makefile.am
+++ b/dnssd/Makefile.am
@@ -1,5 +1,5 @@
# set the include path for X, qt and KDE
-INCLUDES = -I$(top_srcdir) $(all_includes)
+INCLUDES = -I$(top_srcdir) $(all_includes) $(AVAHI_CFLAGS)
# these are the headers for your project
noinst_HEADERS = sdevent.h
@@ -14,7 +14,7 @@ libkdnssd_la_SOURCES = remoteservice.cpp responder.cpp servicebase.cpp \
dnssdincludedir = $(includedir)/dnssd
dnssdinclude_HEADERS = domainbrowser.h query.h remoteservice.h \
publicservice.h servicebase.h servicebrowser.h settings.h
-libkdnssd_la_LIBADD = ../kdecore/libkdecore.la $(LIB_DNSSD)
+libkdnssd_la_LIBADD = ../kdecore/libkdecore.la $(AVAHI_LIBS) $(LIB_QT)
libkdnssd_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -version-info 1:0
#kde_kcfg_DATA = kcm_kdnssd.kcfg
diff --git a/dnssd/README b/dnssd/README
index fd085df95..c797b2939 100644
--- a/dnssd/README
+++ b/dnssd/README
@@ -1,12 +1,11 @@
Checklist to ensure that zeroconf will work:
-1) Install Apple's mdnsd, at least version 85
-2) kdelibs (and kdebase for ksysguard) should be configured and compiled with dns_sd sdk (part
-of mdnsd installation) present - config.h should contain '#define HAVE_DNSSD 1'
+1) Install Avahi, at least version 0.3
+2) compile kdnssd-avahi and install it to replace 'stub' libkdnssd.so provided by kdelibs
3) check /etc/nsswitch.conf and ensure that there is 'mdns' before 'dns' in
line starting with 'host:'. It should be something like:
host: files mdns dns
-4) ensure that mdnsd is being started in initscripts
+4) ensure that avahi-daemon is being started in initscripts
5) for testing: use kpf kicker applet to publish a directory, then open 'zeroconf:/'
URL in konqueror. You should be able to see a local webserver with that published dir.
diff --git a/dnssd/configure.in.in b/dnssd/configure.in.in
index 022ffe871..4eac2441a 100644
--- a/dnssd/configure.in.in
+++ b/dnssd/configure.in.in
@@ -1,38 +1,17 @@
#MIN_CONFIG
-AC_ARG_ENABLE(dnssd, [ --disable-dnssd don't require libdns_sd (browsing and publishing DNS-SD services will not be possible) ], with_dnssd=$enableval, with_dnssd=yes)
-if test "$with_dnssd" = "yes"; then
-AC_MSG_CHECKING(for DNS-SD support)
-save_dnssdtest_LIBS="$LIBS"
-save_dnssdtest_LDFLAGS="$LDFLAGS"
-save_dnssdtest_CPPFLAGS="$CPPFLAGS"
-LDFLAGS="$all_libraries $LDFLAGS"
-CPPFLAGS="$CPPFLAGS $all_includes"
-case $host_os in
- darwin*) LIBS="" ;;
- *) LIBS="-ldns_sd" ;;
-esac
-have_libdns_sd="no"
-AC_TRY_LINK( [
- #include <dns_sd.h>
- ],[
- DNSServiceRefDeallocate( (DNSServiceRef) 0);
- TXTRecordDeallocate( (TXTRecordRef*) 0);
- ],[
- AC_DEFINE(HAVE_DNSSD,1,[Define if dns-sd is available])
- case $host_os in
- darwin*) LIB_DNSSD="" ;;
- *) LIB_DNSSD="-ldns_sd" ;;
- esac
- have_libdns_sd="yes"
- AC_MSG_RESULT(yes)
- ],[
- AC_MSG_RESULT(no)
- LIB_DNSSD=""
-])
-CPPFLAGS=$save_dnssdtest_CPPFLAGS
-LDFLAGS=$save_dnssdtest_LDFLAGS
-LIBS=$save_dnssdtest_LIBS
+# Check for pkg-config manually first, as if its not installed the
+# PKG_PROG_PKG_CONFIG macro won't be defined.
+m4_pattern_allow(PKG_CONFIG_MIN_VERSION)
+AC_CHECK_PROG(have_pkg_config, pkg-config, yes, no)
+
+if test x"$have_pkg_config" == xno; then
+ AC_MSG_ERROR(pkg-config is required to install this program)
fi
-AC_SUBST(LIB_DNSSD)
-AM_CONDITIONAL(HAVE_DNSSD, test "$have_libdns_sd" = "yes")
+
+PKG_PROG_PKG_CONFIG
+
+PKG_CHECK_MODULES( AVAHI, [ avahi-qt3 >= 0.4 , avahi-client >= 0.4 ])
+AC_SUBST(AVAHI_CFLAGS)
+AC_SUBST(AVAHI_LIBS)
+PKG_CHECK_EXISTS( [ avahi-client >= 0.6], AC_DEFINE(AVAHI_API_0_6,1,[Avahi API 0.6] ) )
diff --git a/dnssd/domainbrowser.cpp b/dnssd/domainbrowser.cpp
index cad3307dd..294ce2576 100644
--- a/dnssd/domainbrowser.cpp
+++ b/dnssd/domainbrowser.cpp
@@ -27,46 +27,56 @@
#include "query.h"
#include "servicebrowser.h"
#include <kapplication.h>
+#ifdef AVAHI_API_0_6
+#include <avahi-client/lookup.h>
+#endif
namespace DNSSD
{
-#ifdef HAVE_DNSSD
-void domain_callback(DNSServiceRef, DNSServiceFlags flags, uint32_t, DNSServiceErrorType errorCode,
- const char *replyDomain, void *context);
+#ifdef AVAHI_API_0_6
+void domains_callback(AvahiDomainBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* replyDomain,
+ AvahiLookupResultFlags, void* context);
+#else
+void domains_callback(AvahiDomainBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* replyDomain,
+ void* context);
#endif
-class DomainBrowserPrivate : public Responder
+
+class DomainBrowserPrivate
{
public:
- DomainBrowserPrivate(DomainBrowser* owner) : Responder(), m_browseLAN(false), m_started(false), m_owner(owner) {}
+ DomainBrowserPrivate(DomainBrowser* owner) : m_browseLAN(false), m_started(false),
+ m_browser(0), m_owner(owner) {}
+ ~DomainBrowserPrivate() { if (m_browser) avahi_domain_browser_free(m_browser); }
QStringList m_domains;
virtual void customEvent(QCustomEvent* event);
bool m_browseLAN;
bool m_started;
+ AvahiDomainBrowser* m_browser;
DomainBrowser* m_owner;
};
void DomainBrowserPrivate::customEvent(QCustomEvent* event)
{
- if (event->type()==QEvent::User+SD_ERROR) stop();
if (event->type()==QEvent::User+SD_ADDREMOVE) {
AddRemoveEvent *aev = static_cast<AddRemoveEvent*>(event);
if (aev->m_op==AddRemoveEvent::Add) m_owner->gotNewDomain(aev->m_domain);
else m_owner->gotRemoveDomain(aev->m_domain);
}
}
+
DomainBrowser::DomainBrowser(QObject *parent) : QObject(parent)
{
d = new DomainBrowserPrivate(this);
- d->m_domains = Configuration::domainList();
+ d->m_domains = Configuration::domainList();
if (Configuration::browseLocal()) {
d->m_domains+="local.";
d->m_browseLAN=true;
}
- connect(KApplication::kApplication(),SIGNAL(kipcMessage(int,int)),this,
- SLOT(domainListChanged(int,int)));
+ connect(KApplication::kApplication(),SIGNAL(kipcMessage(int,int)),this,
+ SLOT(domainListChanged(int,int)));
}
DomainBrowser::DomainBrowser(const QStringList& domains, bool recursive, QObject *parent) : QObject(parent)
@@ -88,14 +98,15 @@ void DomainBrowser::startBrowse()
if (d->m_started) return;
d->m_started=true;
if (ServiceBrowser::isAvailable()!=ServiceBrowser::Working) return;
- QStringList::const_iterator itEnd = d->m_domains.end();
+ QStringList::const_iterator itEnd = d->m_domains.end();
for (QStringList::const_iterator it=d->m_domains.begin(); it!=itEnd; ++it ) emit domainAdded(*it);
-#ifdef HAVE_DNSSD
- if (d->m_browseLAN) {
- DNSServiceRef ref;
- if (DNSServiceEnumerateDomains(&ref,kDNSServiceFlagsBrowseDomains,0,domain_callback,
- reinterpret_cast<void*>(d))==kDNSServiceErr_NoError) d->setRef(ref);
- }
+ if (d->m_browseLAN)
+#ifdef AVAHI_API_0_6
+ d->m_browser = avahi_domain_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ "local.", AVAHI_DOMAIN_BROWSER_BROWSE, (AvahiLookupFlags)0, domains_callback, this);
+#else
+ d->m_browser = avahi_domain_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ "local.", AVAHI_DOMAIN_BROWSER_BROWSE, domains_callback, this);
#endif
}
@@ -115,9 +126,14 @@ void DomainBrowser::gotRemoveDomain(const QString& domain)
void DomainBrowser::domainListChanged(int message,int)
{
if (message!=KIPCDomainsChanged) return;
+
bool was_started = d->m_started;
- if (d->isRunning()) d->stop(); // LAN query
+ if (d->m_browser) {
+ avahi_domain_browser_free(d->m_browser); // LAN query
+ d->m_browser=0;
+ }
d->m_started = false;
+
// remove all domains and resolvers
if (was_started) {
QStringList::const_iterator itEnd = d->m_domains.end();
@@ -129,7 +145,7 @@ void DomainBrowser::domainListChanged(int message,int)
Configuration::self()->readConfig();
d->m_browseLAN = Configuration::browseLocal();
d->m_domains = Configuration::domainList();
- if (Configuration::browseLocal()) d->m_domains+="local.";
+ if (Configuration::browseLocal()) d->m_domains+="local";
// this will emit domainAdded() for every domain if necessary
if (was_started) startBrowse();
}
@@ -147,22 +163,21 @@ bool DomainBrowser::isRunning() const
void DomainBrowser::virtual_hook(int, void*)
{}
-#ifdef HAVE_DNSSD
-void domain_callback(DNSServiceRef, DNSServiceFlags flags, uint32_t, DNSServiceErrorType errorCode,
- const char *replyDomain, void *context)
+#ifdef AVAHI_API_0_6
+void domains_callback(AvahiDomainBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* replyDomain,
+ AvahiLookupResultFlags,void* context)
+#else
+void domains_callback(AvahiDomainBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* replyDomain,
+ void* context)
+#endif
{
QObject *obj = reinterpret_cast<QObject*>(context);
- if (errorCode != kDNSServiceErr_NoError) {
- ErrorEvent err;
- QApplication::sendEvent(obj, &err);
- } else {
- AddRemoveEvent arev((flags & kDNSServiceFlagsAdd) ? AddRemoveEvent::Add :
+ AddRemoveEvent* arev=new AddRemoveEvent((event==AVAHI_BROWSER_NEW) ? AddRemoveEvent::Add :
AddRemoveEvent::Remove, QString::null, QString::null,
- DNSToDomain(replyDomain), !(flags & kDNSServiceFlagsMoreComing));
- QApplication::sendEvent(obj, &arev);
- }
+ DNSToDomain(replyDomain));
+ QApplication::postEvent(obj, arev);
}
-#endif
+
}
#include "domainbrowser.moc"
diff --git a/dnssd/publicservice.cpp b/dnssd/publicservice.cpp
index 7ba749c53..ad1ebdbb6 100644
--- a/dnssd/publicservice.cpp
+++ b/dnssd/publicservice.cpp
@@ -30,6 +30,12 @@
#include <network/ksocketaddress.h>
#include <kurl.h>
#include <unistd.h>
+#include <avahi-client/client.h>
+#ifdef AVAHI_API_0_6
+#include <avahi-client/publish.h>
+#endif
+#include <avahi-common/alternative.h>
+#include <avahi-common/strlst.h>
#include "sdevent.h"
#include "responder.h"
#include "servicebrowser.h"
@@ -38,16 +44,23 @@
namespace DNSSD
{
static unsigned long publicIP();
-#ifdef HAVE_DNSSD
-void publish_callback (DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name,
- const char*, const char*, void *context);
-#endif
-class PublicServicePrivate : public Responder
+
+void publish_callback (AvahiEntryGroup*, AvahiEntryGroupState s, void *context);
+
+class PublicServicePrivate
{
public:
- PublicServicePrivate() : m_published(false)
+ PublicServicePrivate() : m_published(false), m_running(false), m_collision(false), m_group(false)
{}
bool m_published;
+ bool m_running;
+ bool m_collision;
+ AvahiEntryGroup* m_group;
+ void commit()
+ {
+ if (!m_collision) avahi_entry_group_commit(m_group);
+ }
+
};
PublicService::PublicService(const QString& name, const QString& type, unsigned int port,
@@ -55,6 +68,10 @@ PublicService::PublicService(const QString& name, const QString& type, unsigned
: QObject(), ServiceBase(name, type, QString::null, domain, port)
{
d = new PublicServicePrivate;
+ if (Responder::self().client()) {
+ d->m_group = avahi_entry_group_new(Responder::self().client(), publish_callback,this);
+ connect(&Responder::self(),SIGNAL(stateChanged(AvahiClientState)),this,SLOT(clientState(AvahiClientState)));
+ }
if (domain.isNull())
if (Configuration::publishType()==Configuration::EnumPublishType::LAN) m_domain="local.";
else m_domain=Configuration::publishDomain();
@@ -63,114 +80,148 @@ PublicService::PublicService(const QString& name, const QString& type, unsigned
PublicService::~PublicService()
{
- stop();
+ if (d->m_group) avahi_entry_group_free(d->m_group);
delete d;
}
+void PublicService::tryApply()
+{
+ if (fillEntryGroup()) d->commit();
+ else {
+ stop();
+ emit published(false);
+ }
+}
+
void PublicService::setServiceName(const QString& serviceName)
{
m_serviceName = serviceName;
- if (d->isRunning()) {
- stop();
- publishAsync();
- }
+ if (d->m_running) {
+ avahi_entry_group_reset(d->m_group);
+ tryApply();
+ }
}
void PublicService::setDomain(const QString& domain)
{
m_domain = domain;
- if (d->isRunning()) {
- stop();
- publishAsync();
- }
+ if (d->m_running) {
+ avahi_entry_group_reset(d->m_group);
+ tryApply();
+ }
}
void PublicService::setType(const QString& type)
{
m_type = type;
- if (d->isRunning()) {
- stop();
- publishAsync();
- }
+ if (d->m_running) {
+ avahi_entry_group_reset(d->m_group);
+ tryApply();
+ }
}
void PublicService::setPort(unsigned short port)
{
m_port = port;
- if (d->isRunning()) {
- stop();
- publishAsync();
- }
+ if (d->m_running) {
+ avahi_entry_group_reset(d->m_group);
+ tryApply();
+ }
}
-bool PublicService::isPublished() const
+void PublicService::setTextData(const QMap<QString,QString>& textData)
{
- return d->m_published;
+ m_textData = textData;
+ if (d->m_running) {
+ avahi_entry_group_reset(d->m_group);
+ tryApply();
+ }
}
-void PublicService::setTextData(const QMap<QString,QString>& textData)
+bool PublicService::isPublished() const
{
- m_textData = textData;
- if (d->isRunning()) {
- stop();
- publishAsync();
- }
+ return d->m_published;
}
bool PublicService::publish()
{
publishAsync();
- while (d->isRunning() && !d->m_published) d->process();
+ while (d->m_running && !d->m_published) Responder::self().process();
return d->m_published;
}
void PublicService::stop()
{
- d->stop();
- d->m_published = false;
+ if (d->m_group) avahi_entry_group_reset(d->m_group);
+ d->m_published = false;
+}
+bool PublicService::fillEntryGroup()
+{
+ AvahiStringList *s=0;
+ QMap<QString,QString>::ConstIterator itEnd = m_textData.end();
+ for (QMap<QString,QString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it)
+ s = avahi_string_list_add_pair(s, it.key().utf8(),it.data().utf8());
+#ifdef AVAHI_API_0_6
+ bool res = (!avahi_entry_group_add_service_strlst(d->m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0,
+ m_serviceName.isNull() ? avahi_client_get_host_name(Responder::self().client()) : m_serviceName.utf8().data(),
+ m_type.ascii(),domainToDNS(m_domain),m_hostName.utf8(),m_port,s));
+#else
+ bool res = (!avahi_entry_group_add_service_strlst(d->m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ m_serviceName.isNull() ? avahi_client_get_host_name(Responder::self().client()) : m_serviceName.utf8().data(),
+ m_type.ascii(),m_domain.utf8(),m_hostName.utf8(),m_port,s));
+#endif
+ avahi_string_list_free(s);
+ return res;
}
+void PublicService::clientState(AvahiClientState s)
+{
+ if (!d->m_running) return;
+ switch (s) {
+#ifdef AVAHI_API_0_6
+ case AVAHI_CLIENT_FAILURE:
+#else
+ case AVAHI_CLIENT_S_INVALID:
+ case AVAHI_CLIENT_DISCONNECTED:
+#endif
+ stop();
+ emit published(false);
+ break;
+ case AVAHI_CLIENT_S_REGISTERING:
+ case AVAHI_CLIENT_S_COLLISION:
+ avahi_entry_group_reset(d->m_group);
+ d->m_collision=true;
+ break;
+ case AVAHI_CLIENT_S_RUNNING:
+ if (d->m_collision) {
+ d->m_collision=false;
+ tryApply();
+ }
+ }
+}
+
void PublicService::publishAsync()
{
- if (d->isRunning()) stop();
-#ifdef HAVE_DNSSD
- if (ServiceBrowser::isAvailable()==ServiceBrowser::Working) {
- TXTRecordRef txt;
- TXTRecordCreate(&txt,0,0);
- QMap<QString,QString>::ConstIterator itEnd = m_textData.end();
- for (QMap<QString,QString>::ConstIterator it = m_textData.begin(); it!=itEnd ; ++it) {
- QCString value = it.data().utf8();
- if (TXTRecordSetValue(&txt,it.key().utf8(),value.length(),value)!=kDNSServiceErr_NoError) {
- TXTRecordDeallocate(&txt);
- emit published(false);
- return;
- }
- }
- DNSServiceRef ref;
- if (DNSServiceRegister(&ref,0,0,m_serviceName.utf8(),m_type.ascii(),domainToDNS(m_domain),NULL,
- htons(m_port),TXTRecordGetLength(&txt),TXTRecordGetBytesPtr(&txt),publish_callback,
- reinterpret_cast<void*>(this)) == kDNSServiceErr_NoError) d->setRef(ref);
- TXTRecordDeallocate(&txt);
+ if (d->m_running) stop();
+
+ if (!d->m_group) {
+ emit published(false);
+ return;
}
-#endif
- if (!d->isRunning()) emit published(false);
+ AvahiClientState s=Responder::self().state();
+ d->m_running=true;
+ d->m_collision=true; // make it look like server is getting out of collision to force registering
+ clientState(s);
}
-#ifdef HAVE_DNSSD
-void publish_callback (DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name,
- const char*, const char*, void *context)
+void publish_callback (AvahiEntryGroup*, AvahiEntryGroupState s, void *context)
{
QObject *obj = reinterpret_cast<QObject*>(context);
- if (errorCode != kDNSServiceErr_NoError) {
- ErrorEvent err;
- QApplication::sendEvent(obj, &err);
- } else {
- PublishEvent pev(QString::fromUtf8(name));
- QApplication::sendEvent(obj, &pev);
- }
+ if (s!=AVAHI_ENTRY_GROUP_ESTABLISHED && s!=AVAHI_ENTRY_GROUP_COLLISION) return;
+ PublishEvent* pev=new PublishEvent(s==AVAHI_ENTRY_GROUP_ESTABLISHED);
+ QApplication::postEvent(obj, pev);
}
-#endif
const KURL PublicService::toInvitation(const QString& host)
{
@@ -194,14 +245,13 @@ const KURL PublicService::toInvitation(const QString& host)
void PublicService::customEvent(QCustomEvent* event)
{
- if (event->type()==QEvent::User+SD_ERROR) {
- stop();
- emit published(false);
- }
if (event->type()==QEvent::User+SD_PUBLISH) {
+ if (!static_cast<PublishEvent*>(event)->m_ok) {
+ setServiceName(QString::fromUtf8(avahi_alternative_service_name(m_serviceName.utf8())));
+ return;
+ }
d->m_published=true;
emit published(true);
- m_serviceName = static_cast<PublishEvent*>(event)->m_name;
}
}
diff --git a/dnssd/publicservice.h b/dnssd/publicservice.h
index 480f071ee..ff090d354 100644
--- a/dnssd/publicservice.h
+++ b/dnssd/publicservice.h
@@ -23,6 +23,7 @@
#include <qobject.h>
#include <dnssd/servicebase.h>
+#include <avahi-client/client.h>
class KURL;
namespace DNSSD
@@ -137,6 +138,10 @@ signals:
void published(bool);
private:
PublicServicePrivate *d;
+ bool fillEntryGroup();
+ void tryApply();
+private slots:
+ void clientState(AvahiClientState);
protected:
virtual void customEvent(QCustomEvent* event);
diff --git a/dnssd/query.cpp b/dnssd/query.cpp
index bcb9c69f5..27b297816 100644
--- a/dnssd/query.cpp
+++ b/dnssd/query.cpp
@@ -22,26 +22,46 @@
#include "responder.h"
#include "remoteservice.h"
#include "sdevent.h"
-#include <kdebug.h>
+#include <qdatetime.h>
#include <qapplication.h>
#include <qtimer.h>
-#define TIMEOUT_WAN 2000
+#include <avahi-client/client.h>
+#ifdef AVAHI_API_0_6
+#include <avahi-client/lookup.h>
+#endif
+
#define TIMEOUT_LAN 200
namespace DNSSD
{
-#ifdef HAVE_DNSSD
-void query_callback (DNSServiceRef, DNSServiceFlags flags, uint32_t, DNSServiceErrorType errorCode,
- const char *serviceName, const char *regtype, const char *replyDomain, void *context);
+#ifdef AVAHI_API_0_6
+
+void services_callback(AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* name,
+ const char* regtype, const char* domain, AvahiLookupResultFlags, void* context);
+void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype,
+ const char* replyDomain, AvahiLookupResultFlags, void* context);
+#else
+void services_callback(AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* name,
+ const char* regtype, const char* domain, void* context);
+void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype,
+ const char* replyDomain, void* context);
+void domains_callback(AvahiDomainBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* replyDomain,
+ void* context);
#endif
-class QueryPrivate : public Responder
+
+enum BrowserType { Types, Services };
+
+class QueryPrivate
{
public:
- QueryPrivate(const QString& type, const QString& domain) : Responder(), m_finished(false),
- m_domain(domain), m_type(type)
- {};
+ QueryPrivate(const QString& type, const QString& domain) : m_finished(false), m_browser(0),
+ m_running(false), m_domain(domain), m_type(type) {}
+
bool m_finished;
+ BrowserType m_browserType;
+ void* m_browser;
+ bool m_running;
QString m_domain;
QTimer timeout;
QString m_type;
@@ -56,12 +76,18 @@ Query::Query(const QString& type, const QString& domain)
Query::~Query()
{
+ if (d->m_browser) {
+ switch (d->m_browserType) {
+ case Services: avahi_service_browser_free((AvahiServiceBrowser*)d->m_browser); break;
+ case Types: avahi_service_type_browser_free((AvahiServiceTypeBrowser*)d->m_browser); break;
+ }
+ }
delete d;
}
bool Query::isRunning() const
{
- return d->isRunning();
+ return d->m_running;
}
bool Query::isFinished() const
@@ -76,16 +102,31 @@ const QString& Query::domain() const
void Query::startQuery()
{
- if (d->isRunning()) return;
+ if (d->m_running) return;
d->m_finished = false;
-#ifdef HAVE_DNSSD
- DNSServiceRef ref;
- if (DNSServiceBrowse(&ref,0,0, d->m_type.ascii(),
- domainToDNS(d->m_domain),query_callback,reinterpret_cast<void*>(this))
- == kDNSServiceErr_NoError) d->setRef(ref);
+ if (d->m_type=="_services._dns-sd._udp") {
+ d->m_browserType = Types;
+#ifdef AVAHI_API_0_6
+ d->m_browser = avahi_service_type_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ domainToDNS(d->m_domain), (AvahiLookupFlags)0, types_callback, this);
+#else
+ d->m_browser = avahi_service_type_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ d->m_domain.utf8(), types_callback, this);
#endif
- if (!d->isRunning()) emit finished();
- else d->timeout.start(domainIsLocal(d->m_domain) ? TIMEOUT_LAN : TIMEOUT_WAN,true);
+ } else {
+ d->m_browserType = Services;
+#ifdef AVAHI_API_0_6
+ d->m_browser = avahi_service_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ d->m_type.ascii(),domainToDNS(d->m_domain), (AvahiLookupFlags)0, services_callback,this);
+#else
+ d->m_browser = avahi_service_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ d->m_type.ascii(),d->m_domain.utf8(),services_callback,this);
+#endif
+ }
+ if (d->m_browser) {
+ d->m_running=true;
+ d->timeout.start(TIMEOUT_LAN,true);
+ } else emit finished();
}
void Query::virtual_hook(int, void*)
{
@@ -93,24 +134,15 @@ void Query::virtual_hook(int, void*)
void Query::customEvent(QCustomEvent* event)
{
- if (event->type()==QEvent::User+SD_ERROR) {
- d->stop();
- d->m_finished=false;
- emit finished();
- }
if (event->type()==QEvent::User+SD_ADDREMOVE) {
- RemoteService* svr;
+ d->timeout.start(TIMEOUT_LAN,true);
+ d->m_finished=false;
AddRemoveEvent *aev = static_cast<AddRemoveEvent*>(event);
// m_type has useless trailing dot
- QString type=aev->m_type.left(aev->m_type.length()-1);
- // label is badly splitted here - _http _tcp.local. . - rely on decode()
- if (d->m_type=="_services._dns-sd._udp") svr = new RemoteService(aev->m_name+"."+
- type+"."+aev->m_domain);
- else svr = new RemoteService(aev->m_name, type, aev->m_domain);
+ RemoteService* svr = new RemoteService(aev->m_name,
+ aev->m_type,aev->m_domain);
if (aev->m_op==AddRemoveEvent::Add) emit serviceAdded(svr);
else emit serviceRemoved(svr);
- d->m_finished = aev->m_last;
- if (d->m_finished) emit finished();
}
}
@@ -119,22 +151,36 @@ void Query::timeout()
d->m_finished=true;
emit finished();
}
-#ifdef HAVE_DNSSD
-void query_callback (DNSServiceRef, DNSServiceFlags flags, uint32_t, DNSServiceErrorType errorCode,
- const char *serviceName, const char *regtype, const char *replyDomain,
- void *context)
+
+#ifdef AVAHI_API_0_6
+void services_callback (AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event,
+ const char* serviceName, const char* regtype, const char* replyDomain, AvahiLookupResultFlags, void* context)
+#else
+void services_callback (AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event,
+ const char* serviceName, const char* regtype, const char* replyDomain, void* context)
+#endif
{
QObject *obj = reinterpret_cast<QObject*>(context);
- if (errorCode != kDNSServiceErr_NoError) {
- ErrorEvent err;
- QApplication::sendEvent(obj, &err);
- } else {
- AddRemoveEvent arev((flags & kDNSServiceFlagsAdd) ? AddRemoveEvent::Add :
+ AddRemoveEvent* arev = new AddRemoveEvent((event==AVAHI_BROWSER_NEW) ? AddRemoveEvent::Add :
AddRemoveEvent::Remove, QString::fromUtf8(serviceName), regtype,
- DNSToDomain(replyDomain), !(flags & kDNSServiceFlagsMoreComing));
- QApplication::sendEvent(obj, &arev);
- }
+ DNSToDomain(replyDomain));
+ QApplication::postEvent(obj, arev);
}
+
+#ifdef AVAHI_API_0_6
+void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype,
+ const char* replyDomain, AvahiLookupResultFlags, void* context)
+#else
+void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype,
+ const char* replyDomain, void* context)
#endif
+{
+ QObject *obj = reinterpret_cast<QObject*>(context);
+ AddRemoveEvent* arev = new AddRemoveEvent((event==AVAHI_BROWSER_NEW) ? AddRemoveEvent::Add :
+ AddRemoveEvent::Remove, QString::null, regtype,
+ DNSToDomain(replyDomain));
+ QApplication::postEvent(obj, arev);
+}
+
}
#include "query.moc"
diff --git a/dnssd/remoteservice.cpp b/dnssd/remoteservice.cpp
index 9d3e4abb6..9fa1a3fe2 100644
--- a/dnssd/remoteservice.cpp
+++ b/dnssd/remoteservice.cpp
@@ -27,33 +27,39 @@
#include <sys/types.h>
#endif
#include <netinet/in.h>
+#include <avahi-client/client.h>
+#include <avahi-common/strlst.h>
+#ifdef AVAHI_API_0_6
+#include <avahi-client/lookup.h>
+#endif
#include "remoteservice.h"
#include "responder.h"
#include "sdevent.h"
-#include <kdebug.h>
namespace DNSSD
{
-#ifdef HAVE_DNSSD
-void resolve_callback ( DNSServiceRef,
- DNSServiceFlags,
- uint32_t,
- DNSServiceErrorType errorCode,
- const char*,
- const char *hosttarget,
- uint16_t port,
- uint16_t txtLen,
- const unsigned char *txtRecord,
- void *context
- );
-
+#ifdef AVAHI_API_0_6
+void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol proto, AvahiResolverEvent e,
+ const char* name, const char* type, const char* domain, const char* hostname, const AvahiAddress* a,
+ uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags, void* context);
+#else
+void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol proto, AvahiResolverEvent e,
+ const char* name, const char* type, const char* domain, const char* hostname, const AvahiAddress* a,
+ uint16_t port, AvahiStringList* txt, void* context);
#endif
+
class RemoteServicePrivate : public Responder
{
public:
- RemoteServicePrivate() : Responder(), m_resolved(false)
- {};
+ RemoteServicePrivate() : m_resolved(false), m_running(false), m_resolver(0) {}
bool m_resolved;
+ bool m_running;
+ AvahiServiceResolver* m_resolver;
+ void stop() {
+ m_running = false;
+ if (m_resolver) avahi_service_resolver_free(m_resolver);
+ m_resolver=0;
+ }
};
RemoteService::RemoteService(const QString& label)
@@ -83,29 +89,33 @@ RemoteService::RemoteService(const KURL& url)
RemoteService::~RemoteService()
{
+ if (d->m_resolver) avahi_service_resolver_free(d->m_resolver);
delete d;
}
bool RemoteService::resolve()
{
resolveAsync();
- while (d->isRunning() && !d->m_resolved) d->process();
+ while (d->m_running && !d->m_resolved) Responder::self().process();
d->stop();
return d->m_resolved;
}
void RemoteService::resolveAsync()
{
- if (d->isRunning()) return;
+ if (d->m_running) return;
d->m_resolved = false;
- kdDebug() << this << ":Starting resolve of : " << m_serviceName << " " << m_type << " " << m_domain << "\n";
-#ifdef HAVE_DNSSD
- DNSServiceRef ref;
- if (DNSServiceResolve(&ref,0,0,m_serviceName.utf8(), m_type.ascii(),
- domainToDNS(m_domain),(DNSServiceResolveReply)resolve_callback,reinterpret_cast<void*>(this))
- == kDNSServiceErr_NoError) d->setRef(ref);
+ // FIXME: first protocol should be set?
+#ifdef AVAHI_API_0_6
+ d->m_resolver = avahi_service_resolver_new(Responder::self().client(),AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ m_serviceName.utf8(), m_type.ascii(), domainToDNS(m_domain), AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_NO_ADDRESS,
+ resolve_callback, this);
+#else
+ d->m_resolver = avahi_service_resolver_new(Responder::self().client(),AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ m_serviceName.utf8(), m_type.ascii(), m_domain.utf8(), AVAHI_PROTO_UNSPEC, resolve_callback, this);
#endif
- if (!d->isRunning()) emit resolved(false);
+ if (d->m_resolver) d->m_running=true;
+ else emit resolved(false);
}
bool RemoteService::isResolved() const
@@ -154,42 +164,33 @@ QDataStream & operator>> (QDataStream & s, RemoteService & a)
return s;
}
-
-#ifdef HAVE_DNSSD
-void resolve_callback ( DNSServiceRef,
- DNSServiceFlags,
- uint32_t,
- DNSServiceErrorType errorCode,
- const char*,
- const char *hosttarget,
- uint16_t port,
- uint16_t txtLen,
- const unsigned char *txtRecord,
- void *context
- )
+#ifdef AVAHI_API_0_6
+void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent e,
+ const char*, const char*, const char*, const char* hostname, const AvahiAddress*,
+ uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags, void* context)
+#else
+void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent e,
+ const char*, const char*, const char*, const char* hostname, const AvahiAddress*,
+ uint16_t port, AvahiStringList* txt, void* context)
+#endif
{
QObject *obj = reinterpret_cast<QObject*>(context);
- if (errorCode != kDNSServiceErr_NoError) {
+ if (e != AVAHI_RESOLVER_FOUND) {
ErrorEvent err;
QApplication::sendEvent(obj, &err);
return;
}
- char key[256];
- int index=0;
- unsigned char valueLen;
- kdDebug() << "Resolve callback\n";
QMap<QString,QString> map;
- const void *voidValue = 0;
- while (TXTRecordGetItemAtIndex(txtLen,txtRecord,index++,256,key,&valueLen,
- &voidValue) == kDNSServiceErr_NoError)
- {
- if (voidValue) map[QString::fromUtf8(key)]=QString::fromUtf8((const char*)voidValue,valueLen);
- else map[QString::fromUtf8(key)]=QString::null;
- }
- ResolveEvent rev(DNSToDomain(hosttarget),ntohs(port),map);
+ while (txt) {
+ char *key, *value;
+ size_t size;
+ if (avahi_string_list_get_pair(txt,&key,&value,&size)) break;
+ map[QString::fromUtf8(key)]=(value) ? QString::fromUtf8(value) : QString::null;
+ txt = txt->next;
+ }
+ ResolveEvent rev(DNSToDomain(hostname),port,map);
QApplication::sendEvent(obj, &rev);
}
-#endif
}
diff --git a/dnssd/responder.cpp b/dnssd/responder.cpp
index 3721d3aae..43be68b28 100644
--- a/dnssd/responder.cpp
+++ b/dnssd/responder.cpp
@@ -20,62 +20,61 @@
#include "responder.h"
#include <qapplication.h>
+#include <qeventloop.h>
+#include <kstaticdeleter.h>
#include <kidna.h>
+#include <kdebug.h>
+#include <avahi-qt3/qt-watch.h>
-// dns_sd.h API should care about proper encoding of non-latin1 characters
-// but for now it does not
-#define IDN_BROKEN_IN_MDNSRESPONDER
namespace DNSSD
{
-Responder::Responder(DNSServiceRef ref,QObject *parent, const char *name)
- : QObject(parent, name), m_ref(0), m_socket(0)
+static KStaticDeleter<Responder> responder_sd;
+Responder* Responder::m_self = 0;
+
+void client_callback(AvahiClient *, AvahiClientState s, void* u)
{
- setRef(ref);
+ Responder *r = reinterpret_cast<Responder*>(u);
+ emit (r->stateChanged(s));
}
-
-void Responder::setRef(DNSServiceRef ref)
+
+
+Responder::Responder()
{
- if (m_socket || m_ref) stop();
- m_running = false;
- m_ref = ref;
- if (m_ref == 0 ) return;
-#ifdef HAVE_DNSSD
- int fd = DNSServiceRefSockFD(ref);
- if (fd == -1) return;
- m_socket = new QSocketNotifier(fd,QSocketNotifier::Read,this);
- connect(m_socket,SIGNAL(activated(int)),this,SLOT(process()));
- m_running = true;
+ int error;
+ const AvahiPoll* poll = avahi_qt_poll_get();
+#ifdef AVAHI_API_0_6
+ m_client = avahi_client_new(poll, AVAHI_CLIENT_IGNORE_USER_CONFIG,client_callback, this, &error);
+#else
+ m_client = avahi_client_new(poll, client_callback, this, &error);
#endif
+ if (!m_client) kdWarning() << "Failed to create avahi client" << endl;
}
+
Responder::~Responder()
{
- stop();
+ if (m_client) avahi_client_free(m_client);
}
-void Responder::stop()
+Responder& Responder::self()
{
- if (m_socket) delete m_socket;
- m_socket = 0;
-#ifdef HAVE_DNSSD
- if (m_ref) DNSServiceRefDeallocate(m_ref);
-#endif
- m_ref = 0;
- m_running = false;
-}
-
+ if (!m_self) responder_sd.setObject(m_self, new Responder);
+ return *m_self;
+}
void Responder::process()
{
-#ifdef HAVE_DNSSD
- if ( DNSServiceProcessResult(m_ref) != kDNSServiceErr_NoError) stop();
-#endif
+ qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
}
-bool Responder::isRunning() const
+AvahiClientState Responder::state() const
{
- return m_running;
+#ifdef AVAHI_API_0_6
+ return (m_client) ? (avahi_client_get_state(m_client)) : AVAHI_CLIENT_FAILURE;
+#else
+ return (m_client) ? (avahi_client_get_state(m_client)) : AVAHI_CLIENT_DISCONNECTED;
+#endif
}
bool domainIsLocal(const QString& domain)
@@ -85,22 +84,14 @@ bool domainIsLocal(const QString& domain)
QCString domainToDNS(const QString &domain)
{
-#ifdef IDN_BROKEN_IN_MDNSRESPONDER
if (domainIsLocal(domain)) return domain.utf8();
else return KIDNA::toAsciiCString(domain);
-#else
- return domain.utf8();
-#endif
}
QString DNSToDomain(const char* domain)
{
-#ifdef IDN_BROKEN_IN_MDNSRESPONDER
if (domainIsLocal(domain)) return QString::fromUtf8(domain);
else return KIDNA::toUnicode(domain);
-#else
- return QString::fromUtf8(domain);
-#endif
}
diff --git a/dnssd/responder.h b/dnssd/responder.h
index 6e36d3357..32ccb7a0b 100644
--- a/dnssd/responder.h
+++ b/dnssd/responder.h
@@ -25,12 +25,7 @@
#include <qsocketnotifier.h>
#include <qsignal.h>
#include <config.h>
-#ifdef HAVE_DNSSD
-#include <dns_sd.h>
-#else
-#define DNSServiceRef void*
-#endif
-
+#include <avahi-client/client.h>
namespace DNSSD
{
@@ -38,30 +33,28 @@ namespace DNSSD
This class should not be used directly.
@author Jakub Stachowski
-@short Internal class wrapping dns_sd.h interface
+@short Internal class wrapping avahi client
*/
class Responder : public QObject
{
Q_OBJECT
public:
- Responder(DNSServiceRef ref=0,QObject *parent = 0, const char *name = 0);
+ Responder();
~Responder();
- /**
- Returns true if it is possible to use mDNS service publishing and discovery.
- It needs mDNSResponder running.
- */
- bool isRunning() const;
- void setRef(DNSServiceRef ref);
- void stop();
-public slots:
+ static Responder& self();
+ AvahiClientState state() const;
+ AvahiClient* client() const { return m_client; }
void process();
-protected:
- DNSServiceRef m_ref;
- bool m_running;
- QSocketNotifier *m_socket;
+signals:
+ void stateChanged(AvahiClientState);
+private:
+ AvahiClient* m_client;
+ static Responder* m_self;
+ friend void client_callback(AvahiClient*, AvahiClientState, void*);
+
};
/* Utils functions */
@@ -71,6 +64,7 @@ bool domainIsLocal(const QString& domain);
QCString domainToDNS(const QString &domain);
QString DNSToDomain(const char* domain);
+
}
#endif
diff --git a/dnssd/sdevent.h b/dnssd/sdevent.h
index 5104839a7..8530e730f 100644
--- a/dnssd/sdevent.h
+++ b/dnssd/sdevent.h
@@ -41,24 +41,23 @@ class AddRemoveEvent : public QCustomEvent
public:
enum Operation { Add, Remove };
AddRemoveEvent(Operation op,const QString& name,const QString& type,
- const QString& domain, bool last) : QCustomEvent(QEvent::User+SD_ADDREMOVE),
- m_op(op), m_name(name), m_type(type), m_domain(domain), m_last(last)
+ const QString& domain) : QCustomEvent(QEvent::User+SD_ADDREMOVE),
+ m_op(op), m_name(name), m_type(type), m_domain(domain)
{}
const Operation m_op;
const QString m_name;
const QString m_type;
const QString m_domain;
- const bool m_last;
};
class PublishEvent : public QCustomEvent
{
public:
- PublishEvent(const QString& name) : QCustomEvent(QEvent::User+SD_PUBLISH), m_name(name)
+ PublishEvent(bool ok) : QCustomEvent(QEvent::User+SD_PUBLISH), m_ok(ok)
{}
- const QString m_name;
+ bool m_ok;
};
class ResolveEvent : public QCustomEvent
diff --git a/dnssd/servicebase.cpp b/dnssd/servicebase.cpp
index ef2943b95..7fd1ef802 100644
--- a/dnssd/servicebase.cpp
+++ b/dnssd/servicebase.cpp
@@ -34,7 +34,7 @@ ServiceBase::~ServiceBase()
QString ServiceBase::encode()
{
- return m_serviceName.replace("\\","\\\\").replace(".","\\.") + QString(".") + m_type +
+ return m_serviceName.replace(".","\\.").replace("\\","\\\\") + QString(".") + m_type +
QString(".") + m_domain;
}
diff --git a/dnssd/servicebrowser.cpp b/dnssd/servicebrowser.cpp
index 017dc8102..542580c1b 100644
--- a/dnssd/servicebrowser.cpp
+++ b/dnssd/servicebrowser.cpp
@@ -23,14 +23,11 @@
#include <qstringlist.h>
#include <qfile.h>
#include "domainbrowser.h"
+#include "responder.h"
#include "query.h"
#include "servicebrowser.h"
+#include <avahi-client/client.h>
#include <config.h>
-#ifdef HAVE_DNSSD
-#include <dns_sd.h>
-#endif
-
-#define MDNSD_PID "/var/run/mdnsd.pid"
namespace DNSSD
{
@@ -85,20 +82,12 @@ ServiceBrowser::ServiceBrowser(const QString& type,const QString& domain,int fla
const ServiceBrowser::State ServiceBrowser::isAvailable()
{
-#ifdef HAVE_DNSSD
- QFile f(MDNSD_PID);
- if (!f.open(IO_ReadOnly)) return Stopped; // no pidfile
- QString line;
- if (f.readLine(line,16)<1) return Stopped;
- unsigned int pid = line.toUInt();
- if (pid==0) return Stopped; // not a pid
- return (kill(pid,0)==0 || errno==EPERM) ? Working : Stopped;
- // signal 0 only checks if process is running, mdnsd is probably owned by 'nobody' so we will
- // get EPERM, if mdnsd is not running error will be ESRCH
-
+ AvahiClientState s = Responder::self().state();
+#ifdef AVAHI_API_0_6
+ return (s==AVAHI_CLIENT_FAILURE) ? Stopped : Working;
#else
- return Unsupported;
-#endif
+ return (s==AVAHI_CLIENT_S_INVALID || s==AVAHI_CLIENT_DISCONNECTED) ? Stopped : Working;
+#endif
}
ServiceBrowser::~ ServiceBrowser()
{