summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2010-03-28 15:46:49 (GMT)
committerRemko Tronçon <git@el-tramo.be>2010-03-28 15:46:49 (GMT)
commitf53a1ef582494458301b97bf6e546be52d7ff7e8 (patch)
tree7571b5cbcbd8a8f1dd1c966c9045b6cb69f0e295 /Swiften/LinkLocal/DNSSD
parent638345680d72ca6acaf123f2c8c1c391f696e371 (diff)
downloadswift-contrib-f53a1ef582494458301b97bf6e546be52d7ff7e8.zip
swift-contrib-f53a1ef582494458301b97bf6e546be52d7ff7e8.tar.bz2
Moving submodule contents back.
Diffstat (limited to 'Swiften/LinkLocal/DNSSD')
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h64
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp60
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h47
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp13
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h22
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h123
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h31
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h73
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h55
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp129
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h50
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp31
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h32
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h55
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h63
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h58
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp8
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h19
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp8
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDQuerier.h29
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp8
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h21
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp8
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h18
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp8
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h28
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp7
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDServiceID.h66
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h22
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp130
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h71
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp20
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h25
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h32
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h27
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h25
-rw-r--r--Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp22
-rw-r--r--Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h12
38 files changed, 1520 insertions, 0 deletions
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h
new file mode 100644
index 0000000..229f97e
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <boost/bind.hpp>
+
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+ class AvahiQuerier;
+
+ class AvahiBrowseQuery : public DNSSDBrowseQuery, public AvahiQuery {
+ public:
+ AvahiBrowseQuery(boost::shared_ptr<AvahiQuerier> q) : AvahiQuery(q) {
+ }
+
+ void startBrowsing() {
+ std::cout << "Start browsing" << std::endl;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ std::cout << "Creating browser" << std::endl;
+ AvahiServiceBrowser* browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, (AvahiLookupFlags) 0, &handleServiceDiscoveredStatic, this);
+ if (!browser) {
+ std::cout << "Error" << std::endl;
+ MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this());
+ }
+ std::cout << "Unlocking" << std::endl;
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+ std::cout << "Browse started" << std::endl;
+ }
+
+ void stopBrowsing() {
+ // TODO
+ }
+
+ private:
+ static void handleServiceDiscoveredStatic(AvahiServiceBrowser *b, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* context) {
+ static_cast<AvahiBrowseQuery*>(context)->handleServiceDiscovered(b, interfaceIndex, protocol, event, name, type, domain, flags);
+ }
+
+ void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) {
+ switch (event) {
+ case AVAHI_BROWSER_FAILURE:
+ std::cout << "Service browse error" << std::endl;
+ MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this());
+ break;
+ case AVAHI_BROWSER_NEW: {
+ DNSSDServiceID service(name, domain, type, interfaceIndex);
+ std::cout << "Service discovered " << name << " " << type << " " << domain << std::endl;
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this());
+ break;
+ }
+ case AVAHI_BROWSER_REMOVE: {
+ std::cout << "Service went away " << name << " " << type << " " << domain << std::endl;
+ DNSSDServiceID service(name, domain, type, interfaceIndex);
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this());
+ break;
+ }
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ break;
+ }
+ }
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp
new file mode 100644
index 0000000..c4bfcb4
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp
@@ -0,0 +1,60 @@
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h"
+
+#include <iostream>
+
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h"
+
+namespace Swift {
+
+AvahiQuerier::AvahiQuerier() : client(NULL), threadedPoll(NULL) {
+}
+
+AvahiQuerier::~AvahiQuerier() {
+}
+
+boost::shared_ptr<DNSSDBrowseQuery> AvahiQuerier::createBrowseQuery() {
+ return boost::shared_ptr<DNSSDBrowseQuery>(new AvahiBrowseQuery(shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDRegisterQuery> AvahiQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) {
+ return boost::shared_ptr<DNSSDRegisterQuery>(new AvahiRegisterQuery(name, port, info, shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDResolveServiceQuery> AvahiQuerier::createResolveServiceQuery(const DNSSDServiceID& service) {
+ return boost::shared_ptr<DNSSDResolveServiceQuery>(new AvahiResolveServiceQuery(service, shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDResolveHostnameQuery> AvahiQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) {
+ return boost::shared_ptr<DNSSDResolveHostnameQuery>(new AvahiResolveHostnameQuery(hostname, interfaceIndex, shared_from_this()));
+}
+
+void AvahiQuerier::start() {
+ std::cout << "Starrting querier" << std::endl;
+ assert(!threadedPoll);
+ threadedPoll = avahi_threaded_poll_new();
+ int error;
+ assert(!client);
+ client = avahi_client_new(
+ avahi_threaded_poll_get(threadedPoll),
+ static_cast<AvahiClientFlags>(0), NULL, this, &error); // TODO
+ if (!client) {
+ // TODO
+ std::cerr << "Avahi Error: " << avahi_strerror(error) << std::endl;
+ return;
+ }
+ std::cout << "Starrting event loop" << std::endl;
+ avahi_threaded_poll_start(threadedPoll);
+}
+
+void AvahiQuerier::stop() {
+ assert(threadedPoll);
+ avahi_threaded_poll_stop(threadedPoll);
+ assert(client);
+ avahi_client_free(client);
+ avahi_threaded_poll_free(threadedPoll);
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h
new file mode 100644
index 0000000..ffb8441
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <avahi-client/client.h>
+#include <avahi-client/lookup.h>
+#include <avahi-common/thread-watch.h>
+#include <avahi-common/watch.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/error.h>
+
+#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
+
+namespace Swift {
+ class ByteArray;
+
+ class AvahiQuerier :
+ public DNSSDQuerier,
+ public boost::enable_shared_from_this<AvahiQuerier> {
+ public:
+ AvahiQuerier();
+ ~AvahiQuerier();
+
+ boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery();
+ boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery(
+ const String& name, int port, const ByteArray& info);
+ boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery(
+ const DNSSDServiceID&);
+ boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery(
+ const String& hostname, int interfaceIndex);
+
+ void start();
+ void stop();
+
+ AvahiThreadedPoll* getThreadedPoll() const {
+ return threadedPoll;
+ }
+
+ AvahiClient* getClient() const {
+ return client;
+ }
+
+ private:
+ AvahiClient* client;
+ AvahiThreadedPoll* threadedPoll;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp
new file mode 100644
index 0000000..6b7c7f9
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp
@@ -0,0 +1,13 @@
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h"
+
+namespace Swift {
+
+AvahiQuery::AvahiQuery(boost::shared_ptr<AvahiQuerier> q) : querier(q) {
+}
+
+AvahiQuery::~AvahiQuery() {
+}
+
+}
+
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h
new file mode 100644
index 0000000..847f3f7
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include "Swiften/EventLoop/EventOwner.h"
+
+namespace Swift {
+ class AvahiQuerier;
+
+ class AvahiQuery :
+ public EventOwner,
+ public boost::enable_shared_from_this<AvahiQuery> {
+ public:
+ AvahiQuery(boost::shared_ptr<AvahiQuerier>);
+ virtual ~AvahiQuery();
+
+ protected:
+ boost::shared_ptr<AvahiQuerier> querier;
+ };
+}
+
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h
new file mode 100644
index 0000000..f42950e
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h
@@ -0,0 +1,123 @@
+#pragma once
+
+#include <avahi-client/publish.h>
+
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h"
+#include "Swiften/Base/ByteArray.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+ class AvahiQuerier;
+
+ class AvahiRegisterQuery : public DNSSDRegisterQuery, public AvahiQuery {
+ public:
+ AvahiRegisterQuery(const String& name, int port, const ByteArray& txtRecord, boost::shared_ptr<AvahiQuerier> querier) : AvahiQuery(querier), name(name), port(port), txtRecord(txtRecord), group(0) {
+ }
+
+ void registerService() {
+ std::cout << "Registering service " << name << ":" << port << std::endl;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ if (!group) {
+ std::cout << "Creating entry group" << std::endl;
+ group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this);
+ if (!group) {
+ std::cout << "Error ceating entry group" << std::endl;
+ MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ }
+
+ doRegisterService();
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+ }
+
+ void unregisterService() {
+ }
+
+ void updateServiceInfo(const ByteArray& txtRecord) {
+ this->txtRecord = txtRecord;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ assert(group);
+ avahi_entry_group_reset(group);
+ doRegisterService();
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+ }
+
+ private:
+ void doRegisterService() {
+ AvahiStringList* txtList;
+ avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList);
+
+ int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags) 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, txtList);
+ if (result < 0) {
+ std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
+ MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ result = avahi_entry_group_commit(group);
+ if (result < 0) {
+ std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
+ }
+ }
+
+ static void handleEntryGroupChange(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) {
+ static_cast<AvahiRegisterQuery*>(userdata)->handleEntryGroupChange(g, state);
+ }
+
+ void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) {
+ std::cout << "ENtry group callback: " << state << std::endl;
+ switch (state) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED :
+ // Domain is a hack!
+ MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this());
+ std::cout << "Entry group established" << std::endl;
+ break;
+ case AVAHI_ENTRY_GROUP_COLLISION : {
+ std::cout << "Entry group collision" << std::endl;
+ /*char *n;
+ n = avahi_alternative_service_name(name);
+ avahi_free(name);
+ name = n;*/
+ break;
+ }
+
+ case AVAHI_ENTRY_GROUP_FAILURE :
+ std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl;
+ break;
+
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ ;
+
+ /*
+ DNSServiceErrorType result = DNSServiceRegister(
+ &sdRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port,
+ txtRecord.getSize(), txtRecord.getData(),
+ &AvahiRegisterQuery::handleServiceRegisteredStatic, this);
+ if (result != kDNSServiceErr_NoError) {
+ sdRef = NULL;
+ }*/
+ //MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ }
+
+/*
+ static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) {
+ static_cast<AvahiRegisterQuery*>(context)->handleServiceRegistered(errorCode, name, regtype, domain);
+ }
+
+ void handleServiceRegistered(DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) {
+ if (errorCode != kDNSServiceErr_NoError) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ else {
+ }
+ }
+ */
+
+ private:
+ String name;
+ int port;
+ ByteArray txtRecord;
+ AvahiEntryGroup* group;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h
new file mode 100644
index 0000000..ee0e837
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "Swiften/Base/String.h"
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+#include "Swiften/Network/HostAddress.h"
+
+#include <netinet/in.h>
+
+namespace Swift {
+ class AvahiQuerier;
+
+ class AvahiResolveHostnameQuery : public DNSSDResolveHostnameQuery, public AvahiQuery {
+ public:
+ AvahiResolveHostnameQuery(const String& hostname, int, boost::shared_ptr<AvahiQuerier> querier) : AvahiQuery(querier), hostname(hostname) {
+ std::cout << "Resolving hostname " << hostname << std::endl;
+ }
+
+ void run() {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(HostAddress(hostname))), shared_from_this());
+ }
+
+ void finish() {
+ }
+
+ private:
+ HostAddress hostAddress;
+ String hostname;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h
new file mode 100644
index 0000000..8577837
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+#include "Swiften/Base/ByteArray.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+ class AvahiQuerier;
+
+ class AvahiResolveServiceQuery : public DNSSDResolveServiceQuery, public AvahiQuery {
+ public:
+ AvahiResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<AvahiQuerier> querier) : AvahiQuery(querier), service(service), resolver(NULL) {
+ }
+
+ void start() {
+ std::cout << "Resolving " << service.getName() << std::endl;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ assert(!resolver);
+ resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().getUTF8Data(), service.getType().getUTF8Data(), service.getDomain().getUTF8Data(), AVAHI_PROTO_UNSPEC, (AvahiLookupFlags) 0, handleServiceResolvedStatic, this);
+ if (!resolver) {
+ std::cout << "Error starting resolver" << std::endl;
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
+ }
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+ }
+
+ void stop() {
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ avahi_service_resolver_free(resolver);
+ resolver = NULL;
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+ }
+
+ private:
+ static void handleServiceResolvedStatic(AvahiServiceResolver* resolver, AvahiIfIndex interfaceIndex, 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* context) {
+ static_cast<AvahiResolveServiceQuery*>(context)->handleServiceResolved(resolver, interfaceIndex, protocol, event, name, type, domain, host_name, address, port, txt, flags);
+ }
+
+ void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) {
+ std::cout << "Resolve finished" << std::endl;
+ switch(event) {
+ case AVAHI_RESOLVER_FAILURE:
+ std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl;
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
+ break;
+ case AVAHI_RESOLVER_FOUND: {
+ char a[AVAHI_ADDRESS_STR_MAX];
+ avahi_address_snprint(a, sizeof(a), address);
+
+ ByteArray txtRecord;
+ txtRecord.resize(1024);
+ avahi_string_list_serialize(txt, txtRecord.getData(), txtRecord.getSize());
+
+ // FIXME: Probably not accurate
+ String fullname = String(name) + "." + String(type) + "." + String(domain) + ".";
+ std::cout << "Result: " << fullname << "->" << String(a) << ":" << port << std::endl;
+ MainEventLoop::postEvent(
+ boost::bind(
+ boost::ref(onServiceResolved),
+ Result(fullname, String(a), port, txtRecord)),
+ shared_from_this());
+ break;
+ }
+ }
+ }
+
+ private:
+ DNSSDServiceID service;
+ AvahiServiceResolver* resolver;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h
new file mode 100644
index 0000000..2dec2fb
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+ class BonjourQuerier;
+
+ class BonjourBrowseQuery : public DNSSDBrowseQuery, public BonjourQuery {
+ public:
+ BonjourBrowseQuery(boost::shared_ptr<BonjourQuerier> q) : BonjourQuery(q) {
+ DNSServiceErrorType result = DNSServiceBrowse(
+ &sdRef, 0, 0, "_presence._tcp", 0,
+ &BonjourBrowseQuery::handleServiceDiscoveredStatic, this);
+ if (result != kDNSServiceErr_NoError) {
+ sdRef = NULL;
+ }
+ }
+
+ void startBrowsing() {
+ if (!sdRef) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this());
+ }
+ else {
+ run();
+ }
+ }
+
+ void stopBrowsing() {
+ finish();
+ }
+
+ private:
+ static void handleServiceDiscoveredStatic(DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *name, const char *type, const char *domain, void *context) {
+ static_cast<BonjourBrowseQuery*>(context)->handleServiceDiscovered(flags, interfaceIndex, errorCode, name, type, domain);
+ }
+
+ void handleServiceDiscovered(DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *name, const char *type, const char *domain) {
+ if (errorCode != kDNSServiceErr_NoError) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this());
+ }
+ else {
+ //std::cout << "Discovered service: name:" << name << " domain:" << domain << " type: " << type << std::endl;
+ DNSSDServiceID service(name, domain, type, interfaceIndex);
+ if (flags & kDNSServiceFlagsAdd) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this());
+ }
+ else {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this());
+ }
+ }
+ }
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp
new file mode 100644
index 0000000..9c9e64e
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp
@@ -0,0 +1,129 @@
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h"
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h"
+#include "Swiften/Base/foreach.h"
+
+namespace Swift {
+
+BonjourQuerier::BonjourQuerier() : stopRequested(false), thread(0) {
+ int fds[2];
+ int result = pipe(fds);
+ assert(result == 0);
+ interruptSelectReadSocket = fds[0];
+ fcntl(interruptSelectReadSocket, F_SETFL, fcntl(interruptSelectReadSocket, F_GETFL)|O_NONBLOCK);
+ interruptSelectWriteSocket = fds[1];
+}
+
+BonjourQuerier::~BonjourQuerier() {
+ assert(!thread);
+}
+
+boost::shared_ptr<DNSSDBrowseQuery> BonjourQuerier::createBrowseQuery() {
+ return boost::shared_ptr<DNSSDBrowseQuery>(new BonjourBrowseQuery(shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDRegisterQuery> BonjourQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) {
+ return boost::shared_ptr<DNSSDRegisterQuery>(new BonjourRegisterQuery(name, port, info, shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDResolveServiceQuery> BonjourQuerier::createResolveServiceQuery(const DNSSDServiceID& service) {
+ return boost::shared_ptr<DNSSDResolveServiceQuery>(new BonjourResolveServiceQuery(service, shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDResolveHostnameQuery> BonjourQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) {
+ return boost::shared_ptr<DNSSDResolveHostnameQuery>(new BonjourResolveHostnameQuery(hostname, interfaceIndex, shared_from_this()));
+}
+
+void BonjourQuerier::addRunningQuery(boost::shared_ptr<BonjourQuery> query) {
+ {
+ boost::lock_guard<boost::mutex> lock(runningQueriesMutex);
+ runningQueries.push_back(query);
+ }
+ runningQueriesAvailableEvent.notify_one();
+ interruptSelect();
+}
+
+void BonjourQuerier::removeRunningQuery(boost::shared_ptr<BonjourQuery> query) {
+ {
+ boost::lock_guard<boost::mutex> lock(runningQueriesMutex);
+ runningQueries.erase(std::remove(
+ runningQueries.begin(), runningQueries.end(), query), runningQueries.end());
+ }
+}
+
+void BonjourQuerier::interruptSelect() {
+ char c = 0;
+ write(interruptSelectWriteSocket, &c, 1);
+}
+
+void BonjourQuerier::start() {
+ assert(!thread);
+ thread = new boost::thread(boost::bind(&BonjourQuerier::run, shared_from_this()));
+}
+
+void BonjourQuerier::stop() {
+ if (thread) {
+ stopRequested = true;
+ assert(runningQueries.empty());
+ runningQueriesAvailableEvent.notify_one();
+ interruptSelect();
+ thread->join();
+ delete thread;
+ thread = NULL;
+ stopRequested = false;
+ }
+}
+
+void BonjourQuerier::run() {
+ while (!stopRequested) {
+ fd_set fdSet;
+ int maxSocket;
+ {
+ boost::unique_lock<boost::mutex> lock(runningQueriesMutex);
+ if (runningQueries.empty()) {
+ runningQueriesAvailableEvent.wait(lock);
+ if (runningQueries.empty()) {
+ continue;
+ }
+ }
+
+ // Run all running queries
+ FD_ZERO(&fdSet);
+ maxSocket = interruptSelectReadSocket;
+ FD_SET(interruptSelectReadSocket, &fdSet);
+
+ foreach(const boost::shared_ptr<BonjourQuery>& query, runningQueries) {
+ int socketID = query->getSocketID();
+ maxSocket = std::max(maxSocket, socketID);
+ FD_SET(socketID, &fdSet);
+ }
+ }
+
+ if (select(maxSocket+1, &fdSet, NULL, NULL, 0) <= 0) {
+ continue;
+ }
+
+ if (FD_ISSET(interruptSelectReadSocket, &fdSet)) {
+ char dummy;
+ while (read(interruptSelectReadSocket, &dummy, 1) > 0) {}
+ }
+
+ {
+ boost::lock_guard<boost::mutex> lock(runningQueriesMutex);
+ foreach(boost::shared_ptr<BonjourQuery> query, runningQueries) {
+ if (FD_ISSET(query->getSocketID(), &fdSet)) {
+ query->processResult();
+ }
+ }
+ }
+ }
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h
new file mode 100644
index 0000000..d12f94f
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <list>
+#include <boost/thread.hpp>
+#include <boost/thread/mutex.hpp>
+
+#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h"
+
+namespace Swift {
+ class ByteArray;
+
+ class BonjourQuerier :
+ public DNSSDQuerier,
+ public boost::enable_shared_from_this<BonjourQuerier> {
+ public:
+ BonjourQuerier();
+ ~BonjourQuerier();
+
+ boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery();
+ boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery(
+ const String& name, int port, const ByteArray& info);
+ boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery(
+ const DNSSDServiceID&);
+ boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery(
+ const String& hostname, int interfaceIndex);
+
+ void start();
+ void stop();
+
+ private:
+ friend class BonjourQuery;
+
+ void addRunningQuery(boost::shared_ptr<BonjourQuery>);
+ void removeRunningQuery(boost::shared_ptr<BonjourQuery>);
+ void interruptSelect();
+ void run();
+
+ private:
+ bool stopRequested;
+ boost::thread* thread;
+ boost::mutex runningQueriesMutex;
+ std::list< boost::shared_ptr<BonjourQuery> > runningQueries;
+ int interruptSelectReadSocket;
+ int interruptSelectWriteSocket;
+ boost::condition_variable runningQueriesAvailableEvent;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp
new file mode 100644
index 0000000..c1c481b
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp
@@ -0,0 +1,31 @@
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h"
+
+namespace Swift {
+
+BonjourQuery::BonjourQuery(boost::shared_ptr<BonjourQuerier> q) : querier(q), sdRef(0) {
+}
+
+BonjourQuery::~BonjourQuery() {
+ DNSServiceRefDeallocate(sdRef);
+}
+
+void BonjourQuery::processResult() {
+ boost::lock_guard<boost::mutex> lock(sdRefMutex);
+ DNSServiceProcessResult(sdRef);
+}
+
+int BonjourQuery::getSocketID() const {
+ boost::lock_guard<boost::mutex> lock(sdRefMutex);
+ return DNSServiceRefSockFD(sdRef);
+}
+
+void BonjourQuery::run() {
+ querier->addRunningQuery(shared_from_this());
+}
+
+void BonjourQuery::finish() {
+ querier->removeRunningQuery(shared_from_this());
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h
new file mode 100644
index 0000000..bdb91a4
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <dns_sd.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/thread/mutex.hpp>
+
+#include "Swiften/EventLoop/EventOwner.h"
+
+namespace Swift {
+ class BonjourQuerier;
+
+ class BonjourQuery :
+ public EventOwner,
+ public boost::enable_shared_from_this<BonjourQuery> {
+ public:
+ BonjourQuery(boost::shared_ptr<BonjourQuerier>);
+ virtual ~BonjourQuery();
+
+ void processResult();
+ int getSocketID() const;
+
+ protected:
+ void run();
+ void finish();
+
+ protected:
+ boost::shared_ptr<BonjourQuerier> querier;
+ mutable boost::mutex sdRefMutex;
+ DNSServiceRef sdRef;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h
new file mode 100644
index 0000000..ddc2788
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h"
+#include "Swiften/Base/ByteArray.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+ class BonjourQuerier;
+
+ class BonjourRegisterQuery : public DNSSDRegisterQuery, public BonjourQuery {
+ public:
+ BonjourRegisterQuery(const String& name, int port, const ByteArray& txtRecord, boost::shared_ptr<BonjourQuerier> querier) : BonjourQuery(querier) {
+ DNSServiceErrorType result = DNSServiceRegister(
+ &sdRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port,
+ txtRecord.getSize(), txtRecord.getData(),
+ &BonjourRegisterQuery::handleServiceRegisteredStatic, this);
+ if (result != kDNSServiceErr_NoError) {
+ sdRef = NULL;
+ }
+ }
+
+ void registerService() {
+ if (sdRef) {
+ run();
+ }
+ else {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ }
+
+ void unregisterService() {
+ finish();
+ }
+
+ void updateServiceInfo(const ByteArray& txtRecord) {
+ boost::lock_guard<boost::mutex> lock(sdRefMutex);
+ DNSServiceUpdateRecord(sdRef, NULL, NULL, txtRecord.getSize(), txtRecord.getData(), 0);
+ }
+
+ private:
+ static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) {
+ static_cast<BonjourRegisterQuery*>(context)->handleServiceRegistered(errorCode, name, regtype, domain);
+ }
+
+ void handleServiceRegistered(DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) {
+ if (errorCode != kDNSServiceErr_NoError) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ else {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, domain, regtype, 0))), shared_from_this());
+ }
+ }
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h
new file mode 100644
index 0000000..7b5f19a
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "Swiften/Base/String.h"
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+#include "Swiften/Network/HostAddress.h"
+
+#include <netinet/in.h>
+
+namespace Swift {
+ class BonjourQuerier;
+
+ class BonjourResolveHostnameQuery : public DNSSDResolveHostnameQuery, public BonjourQuery {
+ public:
+ BonjourResolveHostnameQuery(const String& hostname, int interfaceIndex, boost::shared_ptr<BonjourQuerier> querier) : BonjourQuery(querier) {
+ DNSServiceErrorType result = DNSServiceGetAddrInfo(
+ &sdRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4,
+ hostname.getUTF8Data(),
+ &BonjourResolveHostnameQuery::handleHostnameResolvedStatic, this);
+ if (result != kDNSServiceErr_NoError) {
+ sdRef = NULL;
+ }
+ }
+
+ //void DNSSDResolveHostnameQuery::run() {
+ void run() {
+ if (sdRef) {
+ BonjourQuery::run();
+ }
+ else {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>()), shared_from_this());
+ }
+ }
+
+ void finish() {
+ BonjourQuery::finish();
+ }
+
+ private:
+ static void handleHostnameResolvedStatic(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char*, const struct sockaddr *address, uint32_t, void *context) {
+ static_cast<BonjourResolveHostnameQuery*>(context)->handleHostnameResolved(errorCode, address);
+ }
+
+ void handleHostnameResolved(DNSServiceErrorType errorCode, const struct sockaddr *rawAddress) {
+ if (errorCode) {
+ MainEventLoop::postEvent(
+ boost::bind(boost::ref(onHostnameResolved),
+ boost::optional<HostAddress>()),
+ shared_from_this());
+ }
+ else {
+ assert(rawAddress->sa_family == AF_INET);
+ const sockaddr_in* sa = reinterpret_cast<const sockaddr_in*>(rawAddress);
+ uint32_t address = ntohl(sa->sin_addr.s_addr);
+ MainEventLoop::postEvent(boost::bind(
+ boost::ref(onHostnameResolved),
+ HostAddress(reinterpret_cast<unsigned char*>(&address), 4)),
+ shared_from_this());
+ }
+ }
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h
new file mode 100644
index 0000000..1c38179
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+#include "Swiften/Base/ByteArray.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+ class BonjourQuerier;
+
+ class BonjourResolveServiceQuery : public DNSSDResolveServiceQuery, public BonjourQuery {
+ public:
+ BonjourResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<BonjourQuerier> querier) : BonjourQuery(querier) {
+ DNSServiceErrorType result = DNSServiceResolve(
+ &sdRef, 0, service.getNetworkInterfaceID(),
+ service.getName().getUTF8Data(), service.getType().getUTF8Data(),
+ service.getDomain().getUTF8Data(),
+ &BonjourResolveServiceQuery::handleServiceResolvedStatic, this);
+ if (result != kDNSServiceErr_NoError) {
+ sdRef = NULL;
+ }
+ }
+
+ void start() {
+ if (sdRef) {
+ run();
+ }
+ else {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
+ }
+ }
+
+ void stop() {
+ finish();
+ }
+
+ private:
+ static void handleServiceResolvedStatic(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) {
+ static_cast<BonjourResolveServiceQuery*>(context)->handleServiceResolved(errorCode, fullname, hosttarget, port, txtLen, txtRecord);
+ }
+
+ void handleServiceResolved(DNSServiceErrorType errorCode, const char* fullName, const char* host, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord) {
+ if (errorCode != kDNSServiceErr_NoError) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
+ }
+ else {
+ //std::cout << "Service resolved: name:" << fullName << " host:" << host << " port:" << port << std::endl;
+ MainEventLoop::postEvent(
+ boost::bind(
+ boost::ref(onServiceResolved),
+ Result(String(fullName), String(host), port,
+ ByteArray(reinterpret_cast<const char*>(txtRecord), txtLen))),
+ shared_from_this());
+ }
+ }
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp
new file mode 100644
index 0000000..1dbff2c
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp
@@ -0,0 +1,8 @@
+#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h"
+
+namespace Swift {
+
+DNSSDBrowseQuery::~DNSSDBrowseQuery() {
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h
new file mode 100644
index 0000000..9b30858
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <boost/signal.hpp>
+
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+
+namespace Swift {
+ class DNSSDBrowseQuery {
+ public:
+ virtual ~DNSSDBrowseQuery();
+
+ virtual void startBrowsing() = 0;
+ virtual void stopBrowsing() = 0;
+
+ boost::signal<void (const DNSSDServiceID&)> onServiceAdded;
+ boost::signal<void (const DNSSDServiceID&)> onServiceRemoved;
+ boost::signal<void ()> onError;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp
new file mode 100644
index 0000000..cc8d6ef
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp
@@ -0,0 +1,8 @@
+#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
+
+namespace Swift {
+
+DNSSDQuerier::~DNSSDQuerier() {
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h
new file mode 100644
index 0000000..efcc140
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+ class String;
+ class ByteArray;
+ class DNSSDServiceID;
+ class DNSSDBrowseQuery;
+ class DNSSDRegisterQuery;
+ class DNSSDResolveServiceQuery;
+ class DNSSDResolveHostnameQuery;
+
+ class DNSSDQuerier {
+ public:
+ virtual ~DNSSDQuerier();
+
+ virtual void start() = 0;
+ virtual void stop() = 0;
+
+ virtual boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery() = 0;
+ virtual boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery(
+ const String& name, int port, const ByteArray& info) = 0;
+ virtual boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery(
+ const DNSSDServiceID&) = 0;
+ virtual boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery(
+ const String& hostname, int interfaceIndex) = 0;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp
new file mode 100644
index 0000000..bbb8692
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp
@@ -0,0 +1,8 @@
+#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h"
+
+namespace Swift {
+
+DNSSDRegisterQuery::~DNSSDRegisterQuery() {
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h
new file mode 100644
index 0000000..4a04fa9
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <boost/signal.hpp>
+#include <boost/optional.hpp>
+
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+
+namespace Swift {
+ class ByteArray;
+
+ class DNSSDRegisterQuery {
+ public:
+ virtual ~DNSSDRegisterQuery();
+
+ virtual void registerService() = 0;
+ virtual void unregisterService() = 0;
+ virtual void updateServiceInfo(const ByteArray& info) = 0;
+
+ boost::signal<void (boost::optional<DNSSDServiceID>)> onRegisterFinished;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp
new file mode 100644
index 0000000..e247e39
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp
@@ -0,0 +1,8 @@
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h"
+
+namespace Swift {
+
+DNSSDResolveHostnameQuery::~DNSSDResolveHostnameQuery() {
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h
new file mode 100644
index 0000000..1b9f291
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <boost/signal.hpp>
+#include <boost/optional.hpp>
+
+#include "Swiften/Network/HostAddress.h"
+
+namespace Swift {
+ class DNSSDResolveHostnameQuery {
+ public:
+ virtual ~DNSSDResolveHostnameQuery();
+
+ virtual void run() = 0;
+ virtual void finish() = 0;
+
+ boost::signal<void (const boost::optional<HostAddress>&)> onHostnameResolved;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp
new file mode 100644
index 0000000..67a5d66
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp
@@ -0,0 +1,8 @@
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+
+namespace Swift {
+
+DNSSDResolveServiceQuery::~DNSSDResolveServiceQuery() {
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h
new file mode 100644
index 0000000..217e396
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <boost/signal.hpp>
+#include <boost/optional.hpp>
+
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+#include "Swiften/Base/ByteArray.h"
+
+namespace Swift {
+ class DNSSDResolveServiceQuery {
+ public:
+ struct Result {
+ Result(const String& fullName, const String& host, int port, const ByteArray& info) :
+ fullName(fullName), host(host), port(port), info(info) {}
+ String fullName;
+ String host;
+ int port;
+ ByteArray info;
+ };
+
+ virtual ~DNSSDResolveServiceQuery();
+
+ virtual void start() = 0;
+ virtual void stop() = 0;
+
+ boost::signal<void (const boost::optional<Result>&)> onServiceResolved;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp
new file mode 100644
index 0000000..b360ee5
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp
@@ -0,0 +1,7 @@
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+
+namespace Swift {
+
+const char* DNSSDServiceID::PresenceServiceType = "_presence._tcp";
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h
new file mode 100644
index 0000000..ba7828b
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "Swiften/Base/String.h"
+
+namespace Swift {
+ class DNSSDServiceID {
+ public:
+ static const char* PresenceServiceType;
+
+ DNSSDServiceID(
+ const String& name,
+ const String& domain,
+ const String& type = PresenceServiceType,
+ int networkInterface = 0) :
+ name(name),
+ domain(domain),
+ type(type),
+ networkInterface(networkInterface) {
+ }
+
+ bool operator==(const DNSSDServiceID& o) const {
+ return name == o.name && domain == o.domain && type == o.type && (networkInterface != 0 && o.networkInterface != 0 ? networkInterface == o.networkInterface : true);
+ }
+
+ bool operator<(const DNSSDServiceID& o) const {
+ if (o.name == name) {
+ if (o.domain == domain) {
+ if (o.type == type) {
+ return networkInterface < o.networkInterface;
+ }
+ else {
+ return type < o.type;
+ }
+ }
+ else {
+ return domain < o.domain;
+ }
+ }
+ else {
+ return o.name < name;
+ }
+ }
+
+ const String& getName() const {
+ return name;
+ }
+
+ const String& getDomain() const {
+ return domain;
+ }
+
+ const String& getType() const {
+ return type;
+ }
+
+ int getNetworkInterfaceID() const {
+ return networkInterface;
+ }
+
+ private:
+ String name;
+ String domain;
+ String type;
+ int networkInterface;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h
new file mode 100644
index 0000000..5a0b93b
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h"
+
+namespace Swift {
+ class FakeDNSSDQuerier;
+
+ class FakeDNSSDBrowseQuery : public DNSSDBrowseQuery, public FakeDNSSDQuery {
+ public:
+ FakeDNSSDBrowseQuery(boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier) {
+ }
+
+ void startBrowsing() {
+ run();
+ }
+
+ void stopBrowsing() {
+ finish();
+ }
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
new file mode 100644
index 0000000..c26f8ee
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
@@ -0,0 +1,130 @@
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+
+FakeDNSSDQuerier::FakeDNSSDQuerier(const String& domain) : domain(domain) {
+}
+
+FakeDNSSDQuerier::~FakeDNSSDQuerier() {
+ if (!runningQueries.empty()) {
+ std::cerr << "FakeDNSSDQuerier: Running queries not empty at destruction time" << std::endl;
+ }
+}
+
+boost::shared_ptr<DNSSDBrowseQuery> FakeDNSSDQuerier::createBrowseQuery() {
+ return boost::shared_ptr<DNSSDBrowseQuery>(new FakeDNSSDBrowseQuery(shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDRegisterQuery> FakeDNSSDQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) {
+ return boost::shared_ptr<DNSSDRegisterQuery>(new FakeDNSSDRegisterQuery(name, port, info, shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDResolveServiceQuery> FakeDNSSDQuerier::createResolveServiceQuery(const DNSSDServiceID& service) {
+ return boost::shared_ptr<DNSSDResolveServiceQuery>(new FakeDNSSDResolveServiceQuery(service, shared_from_this()));
+}
+
+boost::shared_ptr<DNSSDResolveHostnameQuery> FakeDNSSDQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) {
+ return boost::shared_ptr<DNSSDResolveHostnameQuery>(new FakeDNSSDResolveHostnameQuery(hostname, interfaceIndex, shared_from_this()));
+}
+
+void FakeDNSSDQuerier::addRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) {
+ runningQueries.push_back(query);
+ if (boost::shared_ptr<FakeDNSSDBrowseQuery> browseQuery = boost::dynamic_pointer_cast<FakeDNSSDBrowseQuery>(query)) {
+ foreach(const DNSSDServiceID& service, services) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(browseQuery->onServiceAdded), service), shared_from_this());
+ }
+ }
+ else if (boost::shared_ptr<FakeDNSSDResolveServiceQuery> resolveQuery = boost::dynamic_pointer_cast<FakeDNSSDResolveServiceQuery>(query)) {
+ for(ServiceInfoMap::const_iterator i = serviceInfo.begin(); i != serviceInfo.end(); ++i) {
+ if (i->first == resolveQuery->service) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(resolveQuery->onServiceResolved), i->second), shared_from_this());
+ }
+ }
+ }
+ else if (boost::shared_ptr<FakeDNSSDRegisterQuery> registerQuery = boost::dynamic_pointer_cast<FakeDNSSDRegisterQuery>(query)) {
+ DNSSDServiceID service(registerQuery->name, domain);
+ MainEventLoop::postEvent(boost::bind(boost::ref(registerQuery->onRegisterFinished), service), shared_from_this());
+ }
+ else if (boost::shared_ptr<FakeDNSSDResolveHostnameQuery> resolveHostnameQuery = boost::dynamic_pointer_cast<FakeDNSSDResolveHostnameQuery>(query)) {
+ std::map<String,boost::optional<HostAddress> >::const_iterator i = addresses.find(resolveHostnameQuery->hostname);
+ if (i != addresses.end()) {
+ MainEventLoop::postEvent(
+ boost::bind(
+ boost::ref(resolveHostnameQuery->onHostnameResolved), i->second),
+ shared_from_this());
+ }
+ }
+}
+
+void FakeDNSSDQuerier::removeRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) {
+ runningQueries.erase(std::remove(
+ runningQueries.begin(), runningQueries.end(), query), runningQueries.end());
+}
+
+void FakeDNSSDQuerier::addService(const DNSSDServiceID& id) {
+ services.insert(id);
+ foreach(const boost::shared_ptr<FakeDNSSDBrowseQuery>& query, getQueries<FakeDNSSDBrowseQuery>()) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(query->onServiceAdded), id), shared_from_this());
+ }
+}
+
+void FakeDNSSDQuerier::removeService(const DNSSDServiceID& id) {
+ services.erase(id);
+ serviceInfo.erase(id);
+ foreach(const boost::shared_ptr<FakeDNSSDBrowseQuery>& query, getQueries<FakeDNSSDBrowseQuery>()) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(query->onServiceRemoved), id), shared_from_this());
+ }
+}
+
+void FakeDNSSDQuerier::setServiceInfo(const DNSSDServiceID& id, const DNSSDResolveServiceQuery::Result& info) {
+ std::pair<ServiceInfoMap::iterator, bool> r = serviceInfo.insert(std::make_pair(id, info));
+ if (!r.second) {
+ r.first->second = info;
+ }
+ foreach(const boost::shared_ptr<FakeDNSSDResolveServiceQuery>& query, getQueries<FakeDNSSDResolveServiceQuery>()) {
+ if (query->service == id) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(query->onServiceResolved), info), shared_from_this());
+ }
+ }
+}
+
+bool FakeDNSSDQuerier::isServiceRegistered(const String& name, int port, const ByteArray& info) {
+ foreach(const boost::shared_ptr<FakeDNSSDRegisterQuery>& query, getQueries<FakeDNSSDRegisterQuery>()) {
+ if (query->name == name && query->port == port && query->info == info) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void FakeDNSSDQuerier::setBrowseError() {
+ foreach(const boost::shared_ptr<FakeDNSSDBrowseQuery>& query, getQueries<FakeDNSSDBrowseQuery>()) {
+ MainEventLoop::postEvent(boost::ref(query->onError), shared_from_this());
+ }
+}
+
+void FakeDNSSDQuerier::setRegisterError() {
+ foreach(const boost::shared_ptr<FakeDNSSDRegisterQuery>& query, getQueries<FakeDNSSDRegisterQuery>()) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(query->onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+}
+
+void FakeDNSSDQuerier::setAddress(const String& hostname, boost::optional<HostAddress> address) {
+ addresses[hostname] = address;
+ foreach(const boost::shared_ptr<FakeDNSSDResolveHostnameQuery>& query, getQueries<FakeDNSSDResolveHostnameQuery>()) {
+ if (query->hostname == hostname) {
+ MainEventLoop::postEvent(boost::bind(
+ boost::ref(query->onHostnameResolved), address), shared_from_this());
+ }
+ }
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
new file mode 100644
index 0000000..22bca0c
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <list>
+#include <set>
+
+#include "Swiften/Base/foreach.h"
+#include "Swiften/Base/String.h"
+#include "Swiften/EventLoop/EventOwner.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/Network/HostAddress.h"
+
+namespace Swift {
+ class ByteArray;
+ class FakeDNSSDQuery;
+ class FakeDNSSDBrowseQuery;
+
+ class FakeDNSSDQuerier :
+ public DNSSDQuerier,
+ public EventOwner,
+ public boost::enable_shared_from_this<FakeDNSSDQuerier> {
+ public:
+ FakeDNSSDQuerier(const String& domain);
+ ~FakeDNSSDQuerier();
+
+ void start() {}
+ void stop() {}
+
+ boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery();
+ boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery(
+ const String& name, int port, const ByteArray& info);
+ boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery(
+ const DNSSDServiceID&);
+ boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery(
+ const String& hostname, int interfaceIndex);
+
+ void addRunningQuery(boost::shared_ptr<FakeDNSSDQuery>);
+ void removeRunningQuery(boost::shared_ptr<FakeDNSSDQuery>);
+
+ void addService(const DNSSDServiceID& id);
+ void removeService(const DNSSDServiceID& id);
+ void setServiceInfo(const DNSSDServiceID& id, const DNSSDResolveServiceQuery::Result& info);
+ bool isServiceRegistered(const String& name, int port, const ByteArray& info);
+ void setAddress(const String& hostname, boost::optional<HostAddress> address);
+
+ void setBrowseError();
+ void setRegisterError();
+
+ private:
+ template<typename T>
+ std::vector< boost::shared_ptr<T> > getQueries() const {
+ std::vector< boost::shared_ptr<T> > result;
+ foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, runningQueries) {
+ if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) {
+ result.push_back(resultQuery);
+ }
+ }
+ return result;
+ }
+
+ private:
+ String domain;
+ std::list< boost::shared_ptr<FakeDNSSDQuery> > runningQueries;
+ std::set<DNSSDServiceID> services;
+ typedef std::map<DNSSDServiceID,DNSSDResolveServiceQuery::Result> ServiceInfoMap;
+ ServiceInfoMap serviceInfo;
+ std::map<String, boost::optional<HostAddress> > addresses;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp
new file mode 100644
index 0000000..ced7850
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp
@@ -0,0 +1,20 @@
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h"
+
+namespace Swift {
+
+FakeDNSSDQuery::FakeDNSSDQuery(boost::shared_ptr<FakeDNSSDQuerier> querier) : querier(querier) {
+}
+
+FakeDNSSDQuery::~FakeDNSSDQuery() {
+}
+
+void FakeDNSSDQuery::run() {
+ querier->addRunningQuery(shared_from_this());
+}
+
+void FakeDNSSDQuery::finish() {
+ querier->removeRunningQuery(shared_from_this());
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h
new file mode 100644
index 0000000..9fca1d4
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include "Swiften/EventLoop/EventOwner.h"
+
+namespace Swift {
+ class FakeDNSSDQuerier;
+
+ class FakeDNSSDQuery :
+ public EventOwner,
+ public boost::enable_shared_from_this<FakeDNSSDQuery> {
+ public:
+ FakeDNSSDQuery(boost::shared_ptr<FakeDNSSDQuerier>);
+ virtual ~FakeDNSSDQuery();
+
+ protected:
+ void run();
+ void finish();
+
+ protected:
+ boost::shared_ptr<FakeDNSSDQuerier> querier;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h
new file mode 100644
index 0000000..82ec623
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h"
+#include "Swiften/Base/ByteArray.h"
+#include "Swiften/Base/String.h"
+
+namespace Swift {
+ class FakeDNSSDQuerier;
+
+ class FakeDNSSDRegisterQuery : public DNSSDRegisterQuery, public FakeDNSSDQuery {
+ public:
+ FakeDNSSDRegisterQuery(const String& name, int port, const ByteArray& info, boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), name(name), port(port), info(info) {
+ }
+
+ void registerService() {
+ run();
+ }
+
+ void updateServiceInfo(const ByteArray& i) {
+ info = i;
+ }
+
+ void unregisterService() {
+ finish();
+ }
+
+ String name;
+ int port;
+ ByteArray info;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h
new file mode 100644
index 0000000..5ed42af
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "Swiften/Base/String.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h"
+#include "Swiften/Network/HostAddress.h"
+
+namespace Swift {
+ class FakeDNSSDQuerier;
+
+ class FakeDNSSDResolveHostnameQuery : public DNSSDResolveHostnameQuery, public FakeDNSSDQuery {
+ public:
+ FakeDNSSDResolveHostnameQuery(const String& hostname, int interfaceIndex, boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), hostname(hostname), interfaceIndex(interfaceIndex) {
+ }
+
+ void run() {
+ FakeDNSSDQuery::run();
+ }
+
+ void finish() {
+ FakeDNSSDQuery::finish();
+ }
+
+ String hostname;
+ int interfaceIndex;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h
new file mode 100644
index 0000000..60d35e5
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+
+namespace Swift {
+ class FakeDNSSDQuerier;
+
+ class FakeDNSSDResolveServiceQuery : public DNSSDResolveServiceQuery, public FakeDNSSDQuery {
+ public:
+ FakeDNSSDResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), service(service) {
+ }
+
+ void start() {
+ run();
+ }
+
+ void stop() {
+ finish();
+ }
+
+ DNSSDServiceID service;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp
new file mode 100644
index 0000000..7b06350
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp
@@ -0,0 +1,22 @@
+#include "Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h"
+
+#if defined(HAVE_BONJOUR)
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h"
+#elif defined(HAVE_AVAHI)
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h"
+#endif
+
+
+namespace Swift {
+
+boost::shared_ptr<DNSSDQuerier> PlatformDNSSDQuerierFactory::createQuerier() {
+#if defined(HAVE_BONJOUR)
+ return boost::shared_ptr<DNSSDQuerier>(new BonjourQuerier());
+#elif defined(HAVE_AVAHI)
+ return boost::shared_ptr<DNSSDQuerier>(new AvahiQuerier());
+#else
+ return boost::shared_ptr<DNSSDQuerier>();
+#endif
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h
new file mode 100644
index 0000000..b52814b
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+ class DNSSDQuerier;
+
+ class PlatformDNSSDQuerierFactory {
+ public:
+ boost::shared_ptr<DNSSDQuerier> createQuerier();
+ };
+}