summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/LinkLocal')
-rw-r--r--Swiften/LinkLocal/AppleDNSSDService.cpp301
-rw-r--r--Swiften/LinkLocal/AppleDNSSDService.h56
-rw-r--r--Swiften/LinkLocal/AvahiDNSSDService.cpp157
-rw-r--r--Swiften/LinkLocal/AvahiDNSSDService.h55
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp59
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h39
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc2
-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/Bonjour/Makefile.inc3
-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.h26
-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.cpp105
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h63
-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.h29
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h25
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/Makefile.inc3
-rw-r--r--Swiften/LinkLocal/DNSSD/Makefile.inc16
-rw-r--r--Swiften/LinkLocal/DNSSDService.cpp8
-rw-r--r--Swiften/LinkLocal/DNSSDService.h74
-rw-r--r--Swiften/LinkLocal/LinkLocalConnector.cpp51
-rw-r--r--Swiften/LinkLocal/LinkLocalConnector.h29
-rw-r--r--Swiften/LinkLocal/LinkLocalRoster.cpp142
-rw-r--r--Swiften/LinkLocal/LinkLocalRoster.h48
-rw-r--r--Swiften/LinkLocal/LinkLocalService.cpp23
-rw-r--r--Swiften/LinkLocal/LinkLocalService.h43
-rw-r--r--Swiften/LinkLocal/LinkLocalServiceBrowser.cpp147
-rw-r--r--Swiften/LinkLocal/LinkLocalServiceBrowser.h63
-rw-r--r--Swiften/LinkLocal/Makefile.inc14
-rw-r--r--Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp379
-rw-r--r--Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp25
-rw-r--r--Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp62
-rw-r--r--Swiften/LinkLocal/UnitTest/Makefile.inc2
53 files changed, 1929 insertions, 891 deletions
diff --git a/Swiften/LinkLocal/AppleDNSSDService.cpp b/Swiften/LinkLocal/AppleDNSSDService.cpp
deleted file mode 100644
index 969cbb2..0000000
--- a/Swiften/LinkLocal/AppleDNSSDService.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-#include "Swiften/LinkLocal/AppleDNSSDService.h"
-
-#include <algorithm>
-#include <unistd.h>
-#include <iostream>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <fcntl.h>
-
-#include "Swiften/EventLoop/MainEventLoop.h"
-#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
-#include "Swiften/Network/HostAddress.h"
-
-namespace Swift {
-
-AppleDNSSDService::AppleDNSSDService() : thread(0), stopRequested(false), haveError(false), browseSDRef(0), registerSDRef(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];
-}
-
-AppleDNSSDService::~AppleDNSSDService() {
- stop();
-}
-
-void AppleDNSSDService::start() {
- stop();
- thread = new boost::thread(boost::bind(&AppleDNSSDService::doStart, shared_from_this()));
-}
-
-void AppleDNSSDService::stop() {
- if (thread) {
- stopRequested = true;
- interruptSelect();
- thread->join();
- delete thread;
- stopRequested = false;
- }
-}
-
-void AppleDNSSDService::registerService(const String& name, int port, const LinkLocalServiceInfo& info) {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-
- assert(!registerSDRef);
- ByteArray txtRecord = info.toTXTRecord();
- DNSServiceErrorType result = DNSServiceRegister(&registerSDRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, txtRecord.getSize(), txtRecord.getData(), &AppleDNSSDService::handleServiceRegisteredGlobal, this);
- if (result != kDNSServiceErr_NoError) {
- std::cerr << "Error creating service registration" << std::endl;
- haveError = true;
- }
-
- interruptSelect();
-}
-
-void AppleDNSSDService::updateService(const LinkLocalServiceInfo& info) {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
- assert(registerSDRef);
- ByteArray txtRecord = info.toTXTRecord();
- DNSServiceUpdateRecord(registerSDRef, NULL, NULL, txtRecord.getSize(), txtRecord.getData(), 0);
-}
-
-void AppleDNSSDService::unregisterService() {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-
- assert(registerSDRef);
- DNSServiceRefDeallocate(registerSDRef); // Interrupts select()
- registerSDRef = NULL;
-}
-
-void AppleDNSSDService::startResolvingService(const Service& service) {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-
- DNSServiceRef resolveSDRef;
- DNSServiceErrorType result = DNSServiceResolve(&resolveSDRef, 0, service.networkInterface, service.name.getUTF8Data(), service.type.getUTF8Data(), service.domain.getUTF8Data(), &AppleDNSSDService::handleServiceResolvedGlobal, this);
- if (result != kDNSServiceErr_NoError) {
- std::cerr << "Error creating service resolve query" << std::endl;
- haveError = true;
- }
- else {
- bool isNew = resolveSDRefs.insert(std::make_pair(service, resolveSDRef)).second;
- assert(isNew);
- }
-
- interruptSelect();
-}
-
-void AppleDNSSDService::stopResolvingService(const Service& service) {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-
- ServiceSDRefMap::iterator i = resolveSDRefs.find(service);
- assert(i != resolveSDRefs.end());
- DNSServiceRefDeallocate(i->second); // Interrupts select()
- resolveSDRefs.erase(i);
-}
-
-void AppleDNSSDService::resolveHostname(const String& hostname, int interfaceIndex) {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-
- DNSServiceRef hostnameResolveSDRef;
- DNSServiceErrorType result = DNSServiceGetAddrInfo(&hostnameResolveSDRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4, hostname.getUTF8Data(), &AppleDNSSDService::handleHostnameResolvedGlobal, this);
- if (result != kDNSServiceErr_NoError) {
- std::cerr << "Error creating hostname resolve query" << std::endl;
- haveError = true;
- }
- else {
- hostnameResolveSDRefs.push_back(hostnameResolveSDRef);
- }
-
- interruptSelect();
-}
-
-void AppleDNSSDService::doStart() {
- haveError = false;
- onStarted();
-
- // Listen for new services
- {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
- assert(!browseSDRef);
- DNSServiceErrorType result = DNSServiceBrowse(&browseSDRef, 0, 0, "_presence._tcp", 0, &AppleDNSSDService::handleServiceDiscoveredGlobal , this);
- if (result != kDNSServiceErr_NoError) {
- std::cerr << "Error creating browse query" << std::endl;
- haveError = true;
- }
- }
-
- // Run the main loop
- while (!haveError && !stopRequested) {
- fd_set fdSet;
- FD_ZERO(&fdSet);
- int maxSocket = interruptSelectReadSocket;
- FD_SET(interruptSelectReadSocket, &fdSet);
-
- {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-
- // Browsing
- int browseSocket = DNSServiceRefSockFD(browseSDRef);
- maxSocket = std::max(maxSocket, browseSocket);
- FD_SET(browseSocket, &fdSet);
-
- // Registration
- if (registerSDRef) {
- int registerSocket = DNSServiceRefSockFD(registerSDRef);
- maxSocket = std::max(maxSocket, registerSocket);
- FD_SET(registerSocket, &fdSet);
- }
-
- // Service resolving
- for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) {
- int resolveSocket = DNSServiceRefSockFD(i->second);
- maxSocket = std::max(maxSocket, resolveSocket);
- FD_SET(resolveSocket, &fdSet);
- }
-
- // Hostname resolving
- for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) {
- int hostnameResolveSocket = DNSServiceRefSockFD(*i);
- maxSocket = std::max(maxSocket, hostnameResolveSocket);
- FD_SET(hostnameResolveSocket, &fdSet);
- }
- }
-
- int selectResult = select(maxSocket+1, &fdSet, NULL, NULL, 0);
-
- // Flush the interruptSelectReadSocket
- if (FD_ISSET(interruptSelectReadSocket, &fdSet)) {
- char dummy;
- while (read(interruptSelectReadSocket, &dummy, 1) > 0) {}
- }
-
- {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
- if (selectResult <= 0) {
- continue;
- }
- if (FD_ISSET(DNSServiceRefSockFD(browseSDRef), &fdSet)) {
- DNSServiceProcessResult(browseSDRef);
- }
- if (registerSDRef && FD_ISSET(DNSServiceRefSockFD(registerSDRef), &fdSet)) {
- DNSServiceProcessResult(registerSDRef);
- }
- for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) {
- if (FD_ISSET(DNSServiceRefSockFD(i->second), &fdSet)) {
- DNSServiceProcessResult(i->second);
- }
- }
- for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) {
- if (FD_ISSET(DNSServiceRefSockFD(*i), &fdSet)) {
- DNSServiceProcessResult(*i);
- hostnameResolveSDRefs.erase(std::remove(hostnameResolveSDRefs.begin(), hostnameResolveSDRefs.end(), *i), hostnameResolveSDRefs.end());
- DNSServiceRefDeallocate(*i);
- break; // Stop the loop, because we removed an element
- }
- }
- }
- }
-
- {
- boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-
- for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) {
- DNSServiceRefDeallocate(i->second);
- }
- resolveSDRefs.clear();
-
- for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) {
- DNSServiceRefDeallocate(*i);
- }
- hostnameResolveSDRefs.clear();
-
- if (registerSDRef) {
- DNSServiceRefDeallocate(registerSDRef);
- registerSDRef = NULL;
- }
-
- DNSServiceRefDeallocate(browseSDRef);
- browseSDRef = NULL;
- }
-
- MainEventLoop::postEvent(boost::bind(boost::ref(onStopped), haveError), shared_from_this());
-}
-
-void AppleDNSSDService::interruptSelect() {
- char c = 0;
- write(interruptSelectWriteSocket, &c, 1);
-}
-
-void AppleDNSSDService::handleServiceDiscoveredGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context ) {
- static_cast<AppleDNSSDService*>(context)->handleServiceDiscovered(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain);
-}
-
-void AppleDNSSDService::handleServiceDiscovered(DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain) {
- if (errorCode != kDNSServiceErr_NoError) {
- return;
- }
- else {
- Service service(serviceName, regtype, replyDomain, 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());
- }
- }
-}
-
-void AppleDNSSDService::handleServiceRegisteredGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) {
- static_cast<AppleDNSSDService*>(context)->handleServiceRegistered(sdRef, flags, errorCode, name, regtype, domain);
-}
-
-void AppleDNSSDService::handleServiceRegistered(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) {
- if (errorCode != kDNSServiceErr_NoError) {
- std::cerr << "Error registering service" << std::endl;
- haveError = true;
- }
- else {
- MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRegistered), Service(name, regtype, domain, 0)), shared_from_this());
- }
-}
-
-void AppleDNSSDService::handleServiceResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context ) {
- static_cast<AppleDNSSDService*>(context)->handleServiceResolved(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtLen, txtRecord);
-}
-
-void AppleDNSSDService::handleServiceResolved(DNSServiceRef sdRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord) {
- if (errorCode != kDNSServiceErr_NoError) {
- // TODO
- std::cerr << "Resolve error " << hosttarget << std::endl;
- return;
- }
- for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) {
- if (i->second == sdRef) {
- MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), i->first, ResolveResult(hosttarget, port, LinkLocalServiceInfo::createFromTXTRecord(ByteArray(reinterpret_cast<const char*>(txtRecord), txtLen)))), shared_from_this());
- return;
- }
- }
- assert(false);
-}
-
-void AppleDNSSDService::handleHostnameResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context) {
- static_cast<AppleDNSSDService*>(context)->handleHostnameResolved(sdRef, flags, interfaceIndex, errorCode, hostname, address, ttl);
-}
-
-void AppleDNSSDService::handleHostnameResolved(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *rawAddress, uint32_t) {
- if (errorCode) {
- std::cerr << "Error resolving hostname" << std::endl;
- MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), hostname, 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), String(hostname), HostAddress(reinterpret_cast<unsigned char*>(&address), 4)), shared_from_this());
- }
-}
-
-}
diff --git a/Swiften/LinkLocal/AppleDNSSDService.h b/Swiften/LinkLocal/AppleDNSSDService.h
deleted file mode 100644
index fe4a648..0000000
--- a/Swiften/LinkLocal/AppleDNSSDService.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#pragma once
-
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/thread.hpp>
-#include <boost/thread/mutex.hpp>
-#include <dns_sd.h>
-
-#include "Swiften/LinkLocal/DNSSDService.h"
-#include "Swiften/EventLoop/EventOwner.h"
-
-namespace Swift {
- class AppleDNSSDService : public DNSSDService, public EventOwner, public boost::enable_shared_from_this<AppleDNSSDService> {
- public:
- AppleDNSSDService();
- ~AppleDNSSDService();
-
- virtual void start();
- virtual void stop();
-
- virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&);
- virtual void updateService(const LinkLocalServiceInfo&);
- virtual void unregisterService();
-
- virtual void startResolvingService(const Service&);
- virtual void stopResolvingService(const Service&);
-
- virtual void resolveHostname(const String& hostname, int interfaceIndex = 0);
-
- private:
- void doStart();
- void interruptSelect();
-
- static void handleServiceDiscoveredGlobal(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, const char *, void*);
- void handleServiceDiscovered(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, const char *);
- static void handleServiceRegisteredGlobal(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType, const char *, const char *, const char *, void *);
- void handleServiceRegistered(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType, const char *, const char *, const char *);
- static void handleServiceResolvedGlobal(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, uint16_t, uint16_t, const unsigned char *, void *);
- void handleServiceResolved(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, uint16_t, uint16_t, const unsigned char *);
- static void handleHostnameResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context);
- void handleHostnameResolved(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl);
-
- private:
- boost::thread* thread;
- bool stopRequested;
- bool haveError;
- int interruptSelectReadSocket;
- int interruptSelectWriteSocket;
- boost::mutex sdRefsMutex;
- DNSServiceRef browseSDRef;
- DNSServiceRef registerSDRef;
- typedef std::map<Service, DNSServiceRef> ServiceSDRefMap;
- ServiceSDRefMap resolveSDRefs;
- typedef std::vector<DNSServiceRef> HostnameSDRefs;
- HostnameSDRefs hostnameResolveSDRefs;
- };
-}
diff --git a/Swiften/LinkLocal/AvahiDNSSDService.cpp b/Swiften/LinkLocal/AvahiDNSSDService.cpp
deleted file mode 100644
index 1dd5c28..0000000
--- a/Swiften/LinkLocal/AvahiDNSSDService.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-#include "Swiften/LinkLocal/AvahiDNSSDService.h"
-
-#include <boost/bind.hpp>
-
-#include "Swiften/EventLoop/MainEventLoop.h"
-#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
-#include "Swiften/Network/HostAddress.h"
-
-namespace Swift {
-
-AvahiDNSSDService::AvahiDNSSDService() : client(NULL), threadedPoll(0), serviceBrowser(0) {
-}
-
-AvahiDNSSDService::~AvahiDNSSDService() {
-}
-
-void AvahiDNSSDService::start() {
- threadedPoll = avahi_threaded_poll_new();
-
- int error;
- 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;
- }
-
- serviceBrowser = avahi_service_browser_new(
- client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
- "_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0),
- handleServiceDiscoveredGlobal, this);
- if (!serviceBrowser) {
- // TODO
- std::cerr << "Avahi Error: " << avahi_strerror(error) << std::endl;
- return;
- }
-
- avahi_threaded_poll_start(threadedPoll);
-}
-
-void AvahiDNSSDService::stop() {
- avahi_threaded_poll_stop(threadedPoll);
- avahi_service_browser_free(serviceBrowser);
- avahi_client_free(client);
- avahi_threaded_poll_free(threadedPoll);
-}
-
-void AvahiDNSSDService::registerService(const String& name, int port, const LinkLocalServiceInfo& info) {
- avahi_threaded_poll_lock(threadedPoll);
- avahi_threaded_poll_unlock(threadedPoll);
-}
-
-void AvahiDNSSDService::updateService(const LinkLocalServiceInfo& info) {
- avahi_threaded_poll_lock(threadedPoll);
- avahi_threaded_poll_unlock(threadedPoll);
-}
-
-void AvahiDNSSDService::unregisterService() {
- avahi_threaded_poll_lock(threadedPoll);
- avahi_threaded_poll_unlock(threadedPoll);
-}
-
-void AvahiDNSSDService::startResolvingService(const Service& service) {
- avahi_threaded_poll_lock(threadedPoll);
-
- AvahiServiceResolver* resolver = avahi_service_resolver_new(
- client,
- service.networkInterface,
- AVAHI_PROTO_INET,
- service.name.getUTF8Data(),
- service.type.getUTF8Data(),
- service.domain.getUTF8Data(),
- AVAHI_PROTO_UNSPEC,
- static_cast<AvahiLookupFlags>(0),
- &AvahiDNSSDService::handleServiceResolvedGlobal,
- this);
- assert(serviceResolvers.find(service) == serviceResolvers.end());
- serviceResolvers[service] = resolver;
-
- avahi_threaded_poll_unlock(threadedPoll);
-}
-
-void AvahiDNSSDService::stopResolvingService(const Service& service) {
- avahi_threaded_poll_lock(threadedPoll);
-
- ServiceResolverMap::iterator i = serviceResolvers.find(service);
- assert(i != serviceResolvers.end());
- avahi_service_resolver_free(i->second);
- serviceResolvers.erase(i);
-
- avahi_threaded_poll_unlock(threadedPoll);
-}
-
-// TODO: Take interfaceIndex into account
-void AvahiDNSSDService::resolveHostname(const String& hostname, int) {
- HostnameAddressMap::const_iterator i = hostnameAddresses.find(hostname);
- if (i == hostnameAddresses.end()) {
- MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), hostname, boost::optional<HostAddress>()), shared_from_this());
- }
- else {
- MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), hostname, boost::optional<HostAddress>(i->second)), shared_from_this());
- }
-}
-
-void AvahiDNSSDService::handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) {
- switch(event) {
- case AVAHI_BROWSER_FAILURE:
- std::cerr << "Browse error" << std::endl;
- // TODO
- return;
- case AVAHI_BROWSER_NEW: {
- std::cerr << "Service added: " << name << " " << type << " " << domain << std::endl;
- Service service(name, type, domain, interfaceIndex);
- MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this());
- }
- break;
- case AVAHI_BROWSER_REMOVE: {
- std::cerr << "Service removed: " << name << " " << type << " " << domain << std::endl;
- Service service(name, type, domain, 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;
- }
-}
-
-void AvahiDNSSDService::handleServiceResolved(AvahiServiceResolver *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) {
- switch(event) {
- case AVAHI_RESOLVER_FAILURE:
- //TODO
- std::cerr << "Resolve error" << std::endl;
- break;
- case AVAHI_RESOLVER_FOUND:
- ByteArray data;
- for(AvahiStringList* i = txt; i; i = avahi_string_list_get_next(i)) {
- char size = i->size;
- data += ByteArray(&size, 1);
- data += ByteArray(reinterpret_cast<char*>(avahi_string_list_get_text(i)), avahi_string_list_get_size(i));
- }
-
- assert(address->proto == AVAHI_PROTO_INET);
- HostAddress hostAddress(reinterpret_cast<const unsigned char*>(&address->data.ipv4.address), 4);
- hostnameAddresses[String(hostname)] = hostAddress;
- MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved),
- Service(name, type, domain, interfaceIndex),
- ResolveResult(hostname, port,
- LinkLocalServiceInfo::createFromTXTRecord(data))),
- shared_from_this());
- break;
- }
-}
-
-}
diff --git a/Swiften/LinkLocal/AvahiDNSSDService.h b/Swiften/LinkLocal/AvahiDNSSDService.h
deleted file mode 100644
index 8d31e41..0000000
--- a/Swiften/LinkLocal/AvahiDNSSDService.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#pragma once
-
-#include <map>
-#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/EventLoop/EventOwner.h"
-#include "Swiften/LinkLocal/DNSSDService.h"
-
-namespace Swift {
- class AvahiDNSSDService : public DNSSDService, public EventOwner, public boost::enable_shared_from_this<AvahiDNSSDService> {
- public:
- AvahiDNSSDService();
- ~AvahiDNSSDService();
-
- virtual void start();
- virtual void stop();
-
- virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&);
- virtual void updateService(const LinkLocalServiceInfo&);
- virtual void unregisterService();
-
- virtual void startResolvingService(const Service&);
- virtual void stopResolvingService(const Service&);
-
- virtual void resolveHostname(const String& hostname, int interfaceIndex = 0);
-
- private:
- static void handleServiceDiscoveredGlobal(AvahiServiceBrowser *b, AvahiIfIndex networkInterface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata) {
- static_cast<AvahiDNSSDService*>(userdata)->handleServiceDiscovered(b, networkInterface, protocol, event, name, type, domain, flags);
- }
- void handleServiceDiscovered(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags);
-
- static void handleServiceResolvedGlobal(AvahiServiceResolver *r, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata) {
- static_cast<AvahiDNSSDService*>(userdata)->handleServiceResolved(r, interfaceIndex, protocol, event, name, type, domain, hostname, address, port, txt, flags);
- }
- void handleServiceResolved(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags);
-
-
- private:
- AvahiClient* client;
- AvahiThreadedPoll* threadedPoll;
- AvahiServiceBrowser* serviceBrowser;
- typedef std::map<Service, AvahiServiceResolver*> ServiceResolverMap;
- ServiceResolverMap serviceResolvers;
- typedef std::map<String, HostAddress> HostnameAddressMap;
- HostnameAddressMap hostnameAddresses;
- };
-}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp
new file mode 100644
index 0000000..55ccede
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp
@@ -0,0 +1,59 @@
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h"
+
+#include <iostream>
+
+//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h"
+//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h"
+//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h"
+//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h"
+//#include "Swiften/Base/foreach.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() {
+ 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;
+ }
+ 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..ca45384
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h
@@ -0,0 +1,39 @@
+#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();
+
+ private:
+ AvahiClient* client;
+ AvahiThreadedPoll* threadedPoll;
+ };
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc b/Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc
new file mode 100644
index 0000000..6150dc1
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc
@@ -0,0 +1,2 @@
+SWIFTEN_SOURCES += \
+ Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h
new file mode 100644
index 0000000..c605175
--- /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..886b87b
--- /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/Bonjour/Makefile.inc b/Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc
new file mode 100644
index 0000000..efa329d
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc
@@ -0,0 +1,3 @@
+SWIFTEN_SOURCES += \
+ Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp \
+ Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp
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..799bc0c
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h
@@ -0,0 +1,26 @@
+#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 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..5079192
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
@@ -0,0 +1,105 @@
+#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) {
+}
+
+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());
+ }
+}
+
+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());
+ }
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
new file mode 100644
index 0000000..f2ec17b
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
@@ -0,0 +1,63 @@
+#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/EventLoop/EventOwner.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.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);
+
+ 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 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;
+ };
+}
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..1f9d7f1
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h
@@ -0,0 +1,29 @@
+#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"
+
+#include <netinet/in.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/Fake/Makefile.inc b/Swiften/LinkLocal/DNSSD/Fake/Makefile.inc
new file mode 100644
index 0000000..316d061
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Fake/Makefile.inc
@@ -0,0 +1,3 @@
+SWIFTEN_SOURCES += \
+ Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp \
+ Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
diff --git a/Swiften/LinkLocal/DNSSD/Makefile.inc b/Swiften/LinkLocal/DNSSD/Makefile.inc
new file mode 100644
index 0000000..f6997ef
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Makefile.inc
@@ -0,0 +1,16 @@
+SWIFTEN_SOURCES += \
+ Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp \
+ Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp \
+ Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp \
+ Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp \
+ Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp \
+ Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp
+
+ifeq ($(HAVE_BONJOUR),yes)
+include Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc
+endif
+ifeq ($(HAVE_AVAHI),yes)
+include Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc
+endif
+
+include Swiften/LinkLocal/DNSSD/Fake/Makefile.inc
diff --git a/Swiften/LinkLocal/DNSSDService.cpp b/Swiften/LinkLocal/DNSSDService.cpp
deleted file mode 100644
index 9545981..0000000
--- a/Swiften/LinkLocal/DNSSDService.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "Swiften/LinkLocal/DNSSDService.h"
-
-namespace Swift {
-
-DNSSDService::~DNSSDService() {
-}
-
-}
diff --git a/Swiften/LinkLocal/DNSSDService.h b/Swiften/LinkLocal/DNSSDService.h
deleted file mode 100644
index 9689352..0000000
--- a/Swiften/LinkLocal/DNSSDService.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#pragma once
-
-#include <boost/signal.hpp>
-#include <map>
-
-#include "Swiften/Base/String.h"
-#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
-
-namespace Swift {
- class LinkLocalServiceInfo;
- class HostAddress;
-
- class DNSSDService {
- public:
- struct Service {
- Service(const String& name, const String& type, const String& domain, int networkInterface) : name(name), type(type), domain(domain), networkInterface(networkInterface) {}
- bool operator==(const Service& o) const {
- return name == o.name && type == o.type && domain == o.domain && (networkInterface != 0 && o.networkInterface != 0 ? networkInterface == o.networkInterface : true);
- }
- bool operator<(const Service& o) const {
- if (o.name == name) {
- if (o.type == type) {
- if (o.domain == domain) {
- return networkInterface < o.networkInterface;
- }
- else {
- return domain < o.domain;
- }
- }
- else {
- return type < o.type;
- }
- }
- else {
- return o.name < name;
- }
- }
-
- String name;
- String type;
- String domain;
- int networkInterface;
- };
-
- struct ResolveResult {
- ResolveResult(const String& host, int port, const LinkLocalServiceInfo& info) : host(host), port(port), info(info) {}
- String host;
- int port;
- LinkLocalServiceInfo info;
- };
-
- virtual ~DNSSDService();
-
- virtual void start() = 0;
- virtual void stop() = 0;
-
- virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&) = 0;
- virtual void updateService(const LinkLocalServiceInfo&) = 0;
- virtual void unregisterService() = 0;
-
- virtual void startResolvingService(const Service&) = 0;
- virtual void stopResolvingService(const Service&) = 0;
-
- virtual void resolveHostname(const String& hostname, int interfaceIndex = 0) = 0;
-
- boost::signal<void ()> onStarted;
- boost::signal<void (bool)> onStopped;
- boost::signal<void (const Service&)> onServiceAdded;
- boost::signal<void (const Service&)> onServiceRemoved;
- boost::signal<void (const Service&)> onServiceRegistered;
- boost::signal<void (const Service&, const ResolveResult&)> onServiceResolved;
- boost::signal<void (const String&, const boost::optional<HostAddress>&)> onHostnameResolved;
- };
-}
diff --git a/Swiften/LinkLocal/LinkLocalConnector.cpp b/Swiften/LinkLocal/LinkLocalConnector.cpp
index af521b0..18b5d6a 100644
--- a/Swiften/LinkLocal/LinkLocalConnector.cpp
+++ b/Swiften/LinkLocal/LinkLocalConnector.cpp
@@ -6,42 +6,45 @@
#include "Swiften/Network/ConnectionFactory.h"
#include "Swiften/Network/HostAddress.h"
#include "Swiften/Network/HostAddressPort.h"
-#include "Swiften/LinkLocal/DNSSDService.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h"
namespace Swift {
LinkLocalConnector::LinkLocalConnector(
const JID& remoteJID,
const String& hostname,
+ int interfaceIndex,
int port,
- boost::shared_ptr<DNSSDService> resolver,
+ boost::shared_ptr<DNSSDQuerier> querier,
boost::shared_ptr<Connection> connection) :
- remoteJID_(remoteJID),
- hostname_(hostname),
- port_(port),
- resolver_(resolver),
- connection_(connection),
- resolving_(false) {
+ remoteJID(remoteJID),
+ hostname(hostname),
+ interfaceIndex(interfaceIndex),
+ port(port),
+ querier(querier),
+ connection(connection) {
}
void LinkLocalConnector::connect() {
- resolving_ = true;
- resolver_->onHostnameResolved.connect(boost::bind(&LinkLocalConnector::handleHostnameResolved, boost::dynamic_pointer_cast<LinkLocalConnector>(shared_from_this()), _1, _2));
- resolver_->resolveHostname(hostname_);
+ resolveQuery = querier->createResolveHostnameQuery(hostname, interfaceIndex);
+ resolveQuery->onHostnameResolved.connect(boost::bind(
+ &LinkLocalConnector::handleHostnameResolved,
+ boost::dynamic_pointer_cast<LinkLocalConnector>(shared_from_this()),
+ _1));
+ resolveQuery->run();
}
-void LinkLocalConnector::handleHostnameResolved(const String& hostname, const boost::optional<HostAddress>& address) {
- if (resolving_) {
- if (hostname == hostname_) {
- resolving_ = false;
- if (address) {
- connection_->onConnectFinished.connect(boost::bind(boost::ref(onConnectFinished), _1));
- connection_->connect(HostAddressPort(*address, port_));
- }
- else {
- onConnectFinished(false);
- }
- }
+void LinkLocalConnector::handleHostnameResolved(const boost::optional<HostAddress>& address) {
+ if (address) {
+ resolveQuery->finish();
+ resolveQuery.reset();
+ connection->onConnectFinished.connect(
+ boost::bind(boost::ref(onConnectFinished), _1));
+ connection->connect(HostAddressPort(*address, port));
+ }
+ else {
+ onConnectFinished(false);
}
}
@@ -50,7 +53,7 @@ void LinkLocalConnector::handleConnected(bool error) {
}
void LinkLocalConnector::queueElement(boost::shared_ptr<Element> element) {
- queuedElements_.push_back(element);
+ queuedElements.push_back(element);
}
diff --git a/Swiften/LinkLocal/LinkLocalConnector.h b/Swiften/LinkLocal/LinkLocalConnector.h
index d296804..134656c 100644
--- a/Swiften/LinkLocal/LinkLocalConnector.h
+++ b/Swiften/LinkLocal/LinkLocalConnector.h
@@ -15,45 +15,48 @@ namespace Swift {
class Element;
class PayloadParserFactoryCollection;
class PayloadSerializerCollection;
- class DNSSDService;
+ class DNSSDQuerier;
+ class DNSSDResolveHostnameQuery;
class LinkLocalConnector : public boost::enable_shared_from_this<LinkLocalConnector> {
public:
LinkLocalConnector(
const JID& remoteJID,
const String& hostname,
+ int interfaceIndex,
int port,
- boost::shared_ptr<DNSSDService> resolver,
+ boost::shared_ptr<DNSSDQuerier> querier,
boost::shared_ptr<Connection> connection);
const JID& getRemoteJID() const {
- return remoteJID_;
+ return remoteJID;
}
void connect();
void queueElement(boost::shared_ptr<Element> element);
const std::vector<boost::shared_ptr<Element> >& getQueuedElements() const {
- return queuedElements_;
+ return queuedElements;
}
boost::shared_ptr<Connection> getConnection() const {
- return connection_;
+ return connection;
}
boost::signal<void (bool)> onConnectFinished;
private:
- void handleHostnameResolved(const String& hostname, const boost::optional<HostAddress>& address);
+ void handleHostnameResolved(const boost::optional<HostAddress>& address);
void handleConnected(bool error);
private:
- JID remoteJID_;
- String hostname_;
- int port_;
- boost::shared_ptr<DNSSDService> resolver_;
- boost::shared_ptr<Connection> connection_;
- bool resolving_;
- std::vector<boost::shared_ptr<Element> > queuedElements_;
+ JID remoteJID;
+ String hostname;
+ int interfaceIndex;
+ int port;
+ boost::shared_ptr<DNSSDQuerier> querier;
+ boost::shared_ptr<DNSSDResolveHostnameQuery> resolveQuery;
+ boost::shared_ptr<Connection> connection;
+ std::vector<boost::shared_ptr<Element> > queuedElements;
};
}
diff --git a/Swiften/LinkLocal/LinkLocalRoster.cpp b/Swiften/LinkLocal/LinkLocalRoster.cpp
deleted file mode 100644
index 25143a6..0000000
--- a/Swiften/LinkLocal/LinkLocalRoster.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#include <boost/bind.hpp>
-#include <iostream>
-
-#include "Swiften/LinkLocal/LinkLocalRoster.h"
-#include "Swiften/Network/HostAddress.h"
-
-namespace Swift {
-
-LinkLocalRoster::LinkLocalRoster(boost::shared_ptr<DNSSDService> service) : dnsSDService(service) {
- dnsSDService->onStopped.connect(boost::bind(&LinkLocalRoster::handleStopped, this, _1));
- dnsSDService->onServiceRegistered.connect(boost::bind(&LinkLocalRoster::handleServiceRegistered, this, _1));
- dnsSDService->onServiceAdded.connect(boost::bind(&LinkLocalRoster::handleServiceAdded, this, _1));
- dnsSDService->onServiceRemoved.connect(boost::bind(&LinkLocalRoster::handleServiceRemoved, this, _1));
- dnsSDService->onServiceResolved.connect(boost::bind(&LinkLocalRoster::handleServiceResolved, this, _1, _2));
-}
-
-boost::shared_ptr<RosterPayload> LinkLocalRoster::getRoster() const {
- boost::shared_ptr<RosterPayload> roster(new RosterPayload());
- for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
- roster->addItem(getRosterItem(i->first, i->second));
- }
- return roster;
-}
-
-std::vector<boost::shared_ptr<Presence> > LinkLocalRoster::getAllPresence() const {
- std::vector<boost::shared_ptr<Presence> > result;
- for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
- result.push_back(getPresence(i->first, i->second));
- }
- return result;
-}
-
-RosterItemPayload LinkLocalRoster::getRosterItem(const DNSSDService::Service& service, const DNSSDService::ResolveResult& resolveResult) const {
- return RosterItemPayload(getJIDForService(service), getRosterName(service, resolveResult), RosterItemPayload::Both);
-}
-
-String LinkLocalRoster::getRosterName(const DNSSDService::Service& service, const DNSSDService::ResolveResult& resolveResult) const {
- if (!resolveResult.info.getNick().isEmpty()) {
- return resolveResult.info.getNick();
- }
- else if (!resolveResult.info.getFirstName().isEmpty()) {
- String result = resolveResult.info.getFirstName();
- if (!resolveResult.info.getLastName().isEmpty()) {
- result += " " + resolveResult.info.getLastName();
- }
- return result;
- }
- else if (!resolveResult.info.getLastName().isEmpty()) {
- return resolveResult.info.getLastName();
- }
- return service.name;
-}
-
-JID LinkLocalRoster::getJIDForService(const DNSSDService::Service& service) const {
- return JID(service.name);
-}
-
-boost::shared_ptr<Presence> LinkLocalRoster::getPresence(const DNSSDService::Service& service, const DNSSDService::ResolveResult& resolveResult) const {
- boost::shared_ptr<Presence> presence(new Presence());
- presence->setFrom(getJIDForService(service));
- switch (resolveResult.info.getStatus()) {
- case LinkLocalServiceInfo::Available:
- presence->setShow(StatusShow::Online);
- break;
- case LinkLocalServiceInfo::Away:
- presence->setShow(StatusShow::Away);
- break;
- case LinkLocalServiceInfo::DND:
- presence->setShow(StatusShow::DND);
- break;
- }
- presence->setStatus(resolveResult.info.getMessage());
- return presence;
-}
-
-void LinkLocalRoster::handleServiceAdded(const DNSSDService::Service& service) {
- if (selfService && *selfService == service) {
- return;
- }
- dnsSDService->startResolvingService(service);
-}
-
-void LinkLocalRoster::handleServiceRemoved(const DNSSDService::Service& service) {
- if (selfService && *selfService == service) {
- return;
- }
- dnsSDService->stopResolvingService(service);
- services.erase(service);
- boost::shared_ptr<RosterPayload> roster(new RosterPayload());
- roster->addItem(RosterItemPayload(getJIDForService(service), "", RosterItemPayload::Remove));
- onRosterChanged(roster);
-}
-
-void LinkLocalRoster::handleServiceResolved(const DNSSDService::Service& service, const DNSSDService::ResolveResult& result) {
- std::pair<ServiceMap::iterator, bool> r = services.insert(std::make_pair(service, result));
- if (r.second) {
- boost::shared_ptr<RosterPayload> roster(new RosterPayload());
- roster->addItem(getRosterItem(service, result));
- onRosterChanged(roster);
- }
- else {
- r.first->second = result;
- }
- onPresenceChanged(getPresence(service, result));
-}
-
-void LinkLocalRoster::handleServiceRegistered(const DNSSDService::Service& service) {
- selfService = service;
-}
-
-void LinkLocalRoster::handleStopped(bool error) {
- std::cout << "DNSSDService stopped: " << error << std::endl;
-}
-
-bool LinkLocalRoster::hasItem(const JID& j) const {
- for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
- if (getJIDForService(i->first) == j) {
- return true;
- }
- }
- return false;
-}
-
-String LinkLocalRoster::getHostname(const JID& j) const {
- for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
- if (getJIDForService(i->first) == j) {
- return i->second.host;
- }
- }
- return "";
-}
-
-int LinkLocalRoster::getPort(const JID& j) const {
- for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
- if (getJIDForService(i->first) == j) {
- return i->second.port;
- }
- }
- return 0;
-}
-
-}
diff --git a/Swiften/LinkLocal/LinkLocalRoster.h b/Swiften/LinkLocal/LinkLocalRoster.h
deleted file mode 100644
index c18d8fc..0000000
--- a/Swiften/LinkLocal/LinkLocalRoster.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#pragma once
-
-#include <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
-#include <set>
-
-#include "Swiften/Base/String.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/LinkLocal/DNSSDService.h"
-#include "Swiften/Elements/RosterPayload.h"
-#include "Swiften/Elements/Presence.h"
-
-namespace Swift {
- class HostAddress;
-
- class LinkLocalRoster {
- public:
- LinkLocalRoster(boost::shared_ptr<DNSSDService> service);
-
- boost::shared_ptr<RosterPayload> getRoster() const;
- std::vector<boost::shared_ptr<Presence> > getAllPresence() const;
-
- boost::signal<void (boost::shared_ptr<RosterPayload>)> onRosterChanged;
- boost::signal<void (boost::shared_ptr<Presence>)> onPresenceChanged;
-
- bool hasItem(const JID&) const;
- String getHostname(const JID&) const;
- int getPort(const JID&) const;
-
- private:
- RosterItemPayload getRosterItem(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const;
- String getRosterName(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const;
- JID getJIDForService(const DNSSDService::Service& service) const;
- boost::shared_ptr<Presence> getPresence(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const;
-
- void handleStopped(bool);
- void handleServiceRegistered(const DNSSDService::Service& service);
- void handleServiceAdded(const DNSSDService::Service&);
- void handleServiceRemoved(const DNSSDService::Service&);
- void handleServiceResolved(const DNSSDService::Service& service, const DNSSDService::ResolveResult& result);
-
- private:
- boost::shared_ptr<DNSSDService> dnsSDService;
- boost::optional<DNSSDService::Service> selfService;
- typedef std::map<DNSSDService::Service, DNSSDService::ResolveResult> ServiceMap;
- ServiceMap services;
- };
-}
diff --git a/Swiften/LinkLocal/LinkLocalService.cpp b/Swiften/LinkLocal/LinkLocalService.cpp
new file mode 100644
index 0000000..f567a63
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalService.cpp
@@ -0,0 +1,23 @@
+#include "Swiften/LinkLocal/LinkLocalService.h"
+
+namespace Swift {
+
+String LinkLocalService::getDescription() const {
+ LinkLocalServiceInfo info = getInfo();
+ if (!info.getNick().isEmpty()) {
+ return info.getNick();
+ }
+ else if (!info.getFirstName().isEmpty()) {
+ String result = info.getFirstName();
+ if (!info.getLastName().isEmpty()) {
+ result += " " + info.getLastName();
+ }
+ return result;
+ }
+ else if (!info.getLastName().isEmpty()) {
+ return info.getLastName();
+ }
+ return getName();
+}
+
+}
diff --git a/Swiften/LinkLocal/LinkLocalService.h b/Swiften/LinkLocal/LinkLocalService.h
new file mode 100644
index 0000000..f7e9e3c
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalService.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "Swiften/Base/String.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+
+namespace Swift {
+ class LinkLocalService {
+ public:
+ LinkLocalService(
+ const DNSSDServiceID& id,
+ const DNSSDResolveServiceQuery::Result& info) :
+ id(id),
+ info(info) {}
+
+ const DNSSDServiceID& getID() const {
+ return id;
+ }
+
+ const String& getName() const {
+ return id.getName();
+ }
+
+ int getPort() const {
+ return info.port;
+ }
+
+ const String& getHostname() const {
+ return info.host;
+ }
+
+ LinkLocalServiceInfo getInfo() const {
+ return LinkLocalServiceInfo::createFromTXTRecord(info.info);
+ }
+
+ String getDescription() const;
+
+ private:
+ DNSSDServiceID id;
+ DNSSDResolveServiceQuery::Result info;
+ };
+}
diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp
new file mode 100644
index 0000000..061bf2c
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp
@@ -0,0 +1,147 @@
+#include <boost/bind.hpp>
+#include <iostream>
+
+#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h"
+#include "Swiften/Network/HostAddress.h"
+
+namespace Swift {
+
+LinkLocalServiceBrowser::LinkLocalServiceBrowser(boost::shared_ptr<DNSSDQuerier> querier) : querier(querier), haveError(false) {
+}
+
+LinkLocalServiceBrowser::~LinkLocalServiceBrowser() {
+ if (isRunning()) {
+ std::cerr << "WARNING: LinkLocalServiceBrowser still running on destruction" << std::endl;
+ }
+}
+
+
+void LinkLocalServiceBrowser::start() {
+ assert(!isRunning());
+ haveError = false;
+ browseQuery = querier->createBrowseQuery();
+ browseQuery->onServiceAdded.connect(
+ boost::bind(&LinkLocalServiceBrowser::handleServiceAdded, this, _1));
+ browseQuery->onServiceRemoved.connect(
+ boost::bind(&LinkLocalServiceBrowser::handleServiceRemoved, this, _1));
+ browseQuery->onError.connect(
+ boost::bind(&LinkLocalServiceBrowser::handleBrowseError, this));
+ browseQuery->startBrowsing();
+}
+
+void LinkLocalServiceBrowser::stop() {
+ assert(isRunning());
+ if (isRegistered()) {
+ unregisterService();
+ }
+ for (ResolveQueryMap::const_iterator i = resolveQueries.begin(); i != resolveQueries.end(); ++i) {
+ i->second->stop();
+ }
+ resolveQueries.clear();
+ services.clear();
+ browseQuery->stopBrowsing();
+ browseQuery.reset();
+ onStopped(haveError);
+}
+
+bool LinkLocalServiceBrowser::isRunning() const {
+ return browseQuery;
+}
+
+bool LinkLocalServiceBrowser::hasError() const {
+ return haveError;
+}
+
+bool LinkLocalServiceBrowser::isRegistered() const {
+ return registerQuery;
+}
+
+void LinkLocalServiceBrowser::registerService(const String& name, int port, const LinkLocalServiceInfo& info) {
+ assert(!registerQuery);
+ registerQuery = querier->createRegisterQuery(name, port, info.toTXTRecord());
+ registerQuery->onRegisterFinished.connect(
+ boost::bind(&LinkLocalServiceBrowser::handleRegisterFinished, this, _1));
+ registerQuery->registerService();
+}
+
+void LinkLocalServiceBrowser::updateService(const LinkLocalServiceInfo& info) {
+ assert(registerQuery);
+ registerQuery->updateServiceInfo(info.toTXTRecord());
+}
+
+void LinkLocalServiceBrowser::unregisterService() {
+ assert(registerQuery);
+ registerQuery->unregisterService();
+ registerQuery.reset();
+ selfService.reset();
+}
+
+std::vector<LinkLocalService> LinkLocalServiceBrowser::getServices() const {
+ std::vector<LinkLocalService> result;
+ for (ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
+ result.push_back(LinkLocalService(i->first, i->second));
+ }
+ return result;
+}
+
+void LinkLocalServiceBrowser::handleServiceAdded(const DNSSDServiceID& service) {
+ if (selfService && service == *selfService) {
+ return;
+ }
+ boost::shared_ptr<DNSSDResolveServiceQuery> resolveQuery = querier->createResolveServiceQuery(service);
+ resolveQuery->onServiceResolved.connect(
+ boost::bind(&LinkLocalServiceBrowser::handleServiceResolved, this, service, _1));
+ std::pair<ResolveQueryMap::iterator, bool> r = resolveQueries.insert(std::make_pair(service, resolveQuery));
+ if (!r.second) {
+ r.first->second = resolveQuery;
+ }
+ resolveQuery->start();
+}
+
+void LinkLocalServiceBrowser::handleServiceRemoved(const DNSSDServiceID& service) {
+ ResolveQueryMap::iterator i = resolveQueries.find(service);
+ if (i == resolveQueries.end()) {
+ // Can happen after an unregister(), when getting the old 'self'
+ // service remove notification.
+ return;
+ }
+ i->second->stop();
+ resolveQueries.erase(i);
+ ServiceMap::iterator j = services.find(service);
+ assert(j != services.end());
+ LinkLocalService linkLocalService(j->first, j->second);
+ services.erase(j);
+ onServiceRemoved(linkLocalService);
+}
+
+void LinkLocalServiceBrowser::handleServiceResolved(const DNSSDServiceID& service, const boost::optional<DNSSDResolveServiceQuery::Result>& result) {
+ if (result) {
+ std::pair<ServiceMap::iterator, bool> r = services.insert(std::make_pair(service, *result));
+ if (r.second) {
+ onServiceAdded(LinkLocalService(r.first->first, r.first->second));
+ }
+ else {
+ r.first->second = *result;
+ onServiceChanged(LinkLocalService(r.first->first, r.first->second));
+ }
+ }
+}
+
+void LinkLocalServiceBrowser::handleRegisterFinished(const boost::optional<DNSSDServiceID>& result) {
+ if (result) {
+ selfService = result;
+ onServiceRegistered(*result);
+ }
+ else {
+ haveError = true;
+ stop();
+ }
+}
+
+void LinkLocalServiceBrowser::handleBrowseError() {
+ haveError = true;
+ stop();
+}
+
+}
diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h
new file mode 100644
index 0000000..7ef661c
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <boost/signal.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include <map>
+#include <vector>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+#include "Swiften/LinkLocal/LinkLocalService.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+
+namespace Swift {
+ class LinkLocalServiceBrowser {
+ public:
+ LinkLocalServiceBrowser(boost::shared_ptr<DNSSDQuerier> querier);
+ ~LinkLocalServiceBrowser();
+
+ void start();
+ void stop();
+ bool isRunning() const;
+ bool hasError() const;
+
+ void registerService(
+ const String& name,
+ int port,
+ const LinkLocalServiceInfo& info = LinkLocalServiceInfo());
+ void updateService(
+ const LinkLocalServiceInfo& info = LinkLocalServiceInfo());
+ void unregisterService();
+ bool isRegistered() const;
+
+ std::vector<LinkLocalService> getServices() const;
+
+ boost::signal<void (const LinkLocalService&)> onServiceAdded;
+ boost::signal<void (const LinkLocalService&)> onServiceChanged;
+ boost::signal<void (const LinkLocalService&)> onServiceRemoved;
+ boost::signal<void (const DNSSDServiceID&)> onServiceRegistered;
+ boost::signal<void (bool)> onStopped;
+
+ private:
+ void handleServiceAdded(const DNSSDServiceID&);
+ void handleServiceRemoved(const DNSSDServiceID&);
+ void handleServiceResolved(const DNSSDServiceID& service, const boost::optional<DNSSDResolveServiceQuery::Result>& result);
+ void handleRegisterFinished(const boost::optional<DNSSDServiceID>&);
+ void handleBrowseError();
+
+ private:
+ boost::shared_ptr<DNSSDQuerier> querier;
+ boost::optional<DNSSDServiceID> selfService;
+ boost::shared_ptr<DNSSDBrowseQuery> browseQuery;
+ boost::shared_ptr<DNSSDRegisterQuery> registerQuery;
+ typedef std::map<DNSSDServiceID, boost::shared_ptr<DNSSDResolveServiceQuery> > ResolveQueryMap;
+ ResolveQueryMap resolveQueries;
+ typedef std::map<DNSSDServiceID, DNSSDResolveServiceQuery::Result> ServiceMap;
+ ServiceMap services;
+ bool haveError;
+ };
+}
diff --git a/Swiften/LinkLocal/Makefile.inc b/Swiften/LinkLocal/Makefile.inc
index 788c000..715d686 100644
--- a/Swiften/LinkLocal/Makefile.inc
+++ b/Swiften/LinkLocal/Makefile.inc
@@ -1,18 +1,10 @@
SWIFTEN_SOURCES += \
- Swiften/LinkLocal/DNSSDService.cpp \
- Swiften/LinkLocal/LinkLocalRoster.cpp \
+ Swiften/LinkLocal/LinkLocalServiceBrowser.cpp \
+ Swiften/LinkLocal/LinkLocalService.cpp \
Swiften/LinkLocal/LinkLocalServiceInfo.cpp \
Swiften/LinkLocal/IncomingLinkLocalSession.cpp \
Swiften/LinkLocal/OutgoingLinkLocalSession.cpp \
Swiften/LinkLocal/LinkLocalConnector.cpp
-ifeq ($(MACOSX),1)
-SWIFTEN_SOURCES += \
- Swiften/LinkLocal/AppleDNSSDService.cpp
-endif
-ifeq ($(HAVE_AVAHI),yes)
-SWIFTEN_SOURCES += \
- Swiften/LinkLocal/AvahiDNSSDService.cpp
-endif
-
+include Swiften/LinkLocal/DNSSD/Makefile.inc
include Swiften/LinkLocal/UnitTest/Makefile.inc
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp
new file mode 100644
index 0000000..9f91269
--- /dev/null
+++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp
@@ -0,0 +1,379 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/bind.hpp>
+#include <map>
+
+#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h"
+#include "Swiften/LinkLocal/LinkLocalService.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h"
+#include "Swiften/EventLoop/DummyEventLoop.h"
+
+using namespace Swift;
+
+class LinkLocalServiceBrowserTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(LinkLocalServiceBrowserTest);
+ CPPUNIT_TEST(testConstructor);
+ CPPUNIT_TEST(testStart);
+ CPPUNIT_TEST(testServiceAdded);
+ CPPUNIT_TEST(testServiceAdded_NoServiceInfo);
+ CPPUNIT_TEST(testServiceAdded_RegisteredService);
+ CPPUNIT_TEST(testServiceAdded_UnregisteredService);
+ CPPUNIT_TEST(testServiceChanged);
+ CPPUNIT_TEST(testServiceRemoved);
+ CPPUNIT_TEST(testServiceRemoved_UnregisteredService);
+ CPPUNIT_TEST(testError_BrowseErrorAfterStart);
+ CPPUNIT_TEST(testError_BrowseErrorAfterResolve);
+ CPPUNIT_TEST(testRegisterService);
+ CPPUNIT_TEST(testRegisterService_Error);
+ CPPUNIT_TEST(testRegisterService_Reregister);
+ CPPUNIT_TEST(testUpdateService);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ LinkLocalServiceBrowserTest() {}
+
+ void setUp() {
+ eventLoop = new DummyEventLoop();
+ querier = boost::shared_ptr<FakeDNSSDQuerier>(new FakeDNSSDQuerier("wonderland.lit"));
+ aliceServiceID = new DNSSDServiceID("alice", "wonderland.lit");
+ aliceServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.wonderland.lit", "xmpp.wonderland.lit", 1234, LinkLocalServiceInfo().toTXTRecord());
+ testServiceID = new DNSSDServiceID("foo", "bar.local");
+ testServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.bar.local", "xmpp.bar.local", 1234, LinkLocalServiceInfo().toTXTRecord());
+ testServiceInfo2 = new DNSSDResolveServiceQuery::Result("_presence.tcp.bar.local", "xmpp.foo.local", 2345, LinkLocalServiceInfo().toTXTRecord());
+ errorStopReceived = false;
+ normalStopReceived = false;
+ }
+
+ void tearDown() {
+ addedServices.clear();
+ removedServices.clear();
+ changedServices.clear();
+
+ delete aliceServiceID;
+ delete aliceServiceInfo;
+ delete testServiceInfo2;
+ delete testServiceInfo;
+ delete testServiceID;
+ delete eventLoop;
+ }
+
+ void testConstructor() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+
+ CPPUNIT_ASSERT(!testling->isRunning());
+ CPPUNIT_ASSERT(!testling->hasError());
+ }
+
+ void testStart() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+
+ CPPUNIT_ASSERT(testling->isRunning());
+ CPPUNIT_ASSERT(!testling->hasError());
+
+ testling->stop();
+ }
+
+ void testServiceAdded() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+
+ querier->setServiceInfo(*testServiceID,*testServiceInfo);
+ querier->addService(*testServiceID);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size()));
+ CPPUNIT_ASSERT(addedServices[0].getID() == *testServiceID);
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size()));
+ std::vector<LinkLocalService> services = testling->getServices();
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(services.size()));
+ CPPUNIT_ASSERT(*testServiceID == services[0].getID());
+ CPPUNIT_ASSERT(testServiceInfo->port == services[0].getPort());
+ CPPUNIT_ASSERT(testServiceInfo->host == services[0].getHostname());
+
+ testling->stop();
+ }
+
+ void testServiceAdded_NoServiceInfo() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+
+ querier->addService(*testServiceID);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(addedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size()));
+
+ testling->stop();
+ }
+
+ void testServiceAdded_RegisteredService() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+
+ testling->registerService("alice", 1234, LinkLocalServiceInfo());
+ eventLoop->processEvents();
+ querier->setServiceInfo(*aliceServiceID, *aliceServiceInfo);
+ querier->addService(*aliceServiceID);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(addedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size()));
+
+ testling->stop();
+ }
+
+ void testServiceAdded_UnregisteredService() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+ testling->registerService("alice", 1234, LinkLocalServiceInfo());
+ eventLoop->processEvents();
+ testling->unregisterService();
+ eventLoop->processEvents();
+
+ querier->setServiceInfo(*aliceServiceID, *aliceServiceInfo);
+ querier->addService(*aliceServiceID);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size()));
+ CPPUNIT_ASSERT(addedServices[0].getID() == *aliceServiceID);
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size()));
+ std::vector<LinkLocalService> services = testling->getServices();
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(services.size()));
+ CPPUNIT_ASSERT(*aliceServiceID == services[0].getID());
+ CPPUNIT_ASSERT(aliceServiceInfo->port == services[0].getPort());
+ CPPUNIT_ASSERT(aliceServiceInfo->host == services[0].getHostname());
+
+ testling->stop();
+ }
+
+ void testServiceRemoved_UnregisteredService() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+ testling->registerService("alice", 1234, LinkLocalServiceInfo());
+ eventLoop->processEvents();
+ testling->unregisterService();
+ eventLoop->processEvents();
+
+ querier->removeService(*aliceServiceID);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size()));
+
+ testling->stop();
+ }
+
+ void testServiceChanged() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ querier->setServiceInfo(*testServiceID,*testServiceInfo);
+ querier->addService(*testServiceID);
+ eventLoop->processEvents();
+
+ querier->setServiceInfo(*testServiceID,*testServiceInfo2);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size()));
+ CPPUNIT_ASSERT(changedServices[0].getID() == *testServiceID);
+ std::vector<LinkLocalService> services = testling->getServices();
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(services.size()));
+ CPPUNIT_ASSERT(*testServiceID == services[0].getID());
+ CPPUNIT_ASSERT(testServiceInfo2->port == services[0].getPort());
+ CPPUNIT_ASSERT(testServiceInfo2->host == services[0].getHostname());
+
+ testling->stop();
+ }
+
+ void testServiceRemoved() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ querier->setServiceInfo(*testServiceID,*testServiceInfo);
+ querier->addService(*testServiceID);
+ eventLoop->processEvents();
+
+ querier->removeService(*testServiceID);
+ eventLoop->processEvents();
+ querier->setServiceInfo(*testServiceID,*testServiceInfo2);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(removedServices.size()));
+ CPPUNIT_ASSERT(removedServices[0].getID() == *testServiceID);
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size()));
+
+ testling->stop();
+ }
+
+ void testError_BrowseErrorAfterStart() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+
+ querier->setBrowseError();
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(!testling->isRunning());
+ CPPUNIT_ASSERT(testling->hasError());
+ CPPUNIT_ASSERT(errorStopReceived);
+ }
+
+ void testError_BrowseErrorAfterResolve() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ querier->setServiceInfo(*testServiceID,*testServiceInfo);
+ querier->addService(*testServiceID);
+ eventLoop->processEvents();
+
+ querier->setBrowseError();
+ eventLoop->processEvents();
+ querier->setServiceInfo(*testServiceID,*testServiceInfo2);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(!testling->isRunning());
+ CPPUNIT_ASSERT(testling->hasError());
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size()));
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size()));
+ CPPUNIT_ASSERT(errorStopReceived);
+ }
+
+ void testRegisterService() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+
+ LinkLocalServiceInfo info;
+ info.setFirstName("Foo");
+ testling->registerService("foo@bar", 1234, info);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(registeredServices.size()));
+ CPPUNIT_ASSERT(registeredServices[0] == DNSSDServiceID("foo@bar", "wonderland.lit"));
+ testling->stop();
+ }
+
+ void testRegisterService_Error() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ LinkLocalServiceInfo info;
+ testling->registerService("foo@bar", 1234, info);
+ eventLoop->processEvents();
+
+ querier->setRegisterError();
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(!testling->isRunning());
+ CPPUNIT_ASSERT(testling->hasError());
+ CPPUNIT_ASSERT(errorStopReceived);
+ CPPUNIT_ASSERT(!querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord()));
+ }
+
+ void testRegisterService_Reregister() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+ LinkLocalServiceInfo info;
+ info.setFirstName("Foo");
+ testling->registerService("foo@bar", 1234, info);
+ eventLoop->processEvents();
+ testling->unregisterService();
+ eventLoop->processEvents();
+
+ info.setFirstName("Bar");
+ testling->registerService("bar@baz", 3456, info);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(querier->isServiceRegistered("bar@baz", 3456, info.toTXTRecord()));
+
+ testling->stop();
+ }
+
+ void testUpdateService() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+ testling->start();
+ eventLoop->processEvents();
+
+ LinkLocalServiceInfo info;
+ info.setFirstName("Foo");
+ testling->registerService("foo@bar", 1234, info);
+ eventLoop->processEvents();
+ info.setFirstName("Bar");
+ testling->updateService(info);
+
+ CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord()));
+
+ testling->stop();
+ }
+
+ private:
+ boost::shared_ptr<LinkLocalServiceBrowser> createTestling() {
+ boost::shared_ptr<LinkLocalServiceBrowser> testling(
+ new LinkLocalServiceBrowser(querier));
+ testling->onServiceAdded.connect(boost::bind(
+ &LinkLocalServiceBrowserTest::handleServiceAdded, this, _1));
+ testling->onServiceChanged.connect(boost::bind(
+ &LinkLocalServiceBrowserTest::handleServiceChanged, this, _1));
+ testling->onServiceRemoved.connect(boost::bind(
+ &LinkLocalServiceBrowserTest::handleServiceRemoved, this, _1));
+ testling->onServiceRegistered.connect(boost::bind(
+ &LinkLocalServiceBrowserTest::handleServiceRegistered, this, _1));
+ testling->onStopped.connect(boost::bind(
+ &LinkLocalServiceBrowserTest::handleStopped, this, _1));
+ return testling;
+ }
+
+ void handleServiceAdded(const LinkLocalService& service) {
+ addedServices.push_back(service);
+ }
+
+ void handleServiceRemoved(const LinkLocalService& service) {
+ removedServices.push_back(service);
+ }
+
+ void handleServiceChanged(const LinkLocalService& service) {
+ changedServices.push_back(service);
+ }
+
+ void handleServiceRegistered(const DNSSDServiceID& service) {
+ registeredServices.push_back(service);
+ }
+
+ void handleStopped(bool error) {
+ CPPUNIT_ASSERT(!errorStopReceived);
+ CPPUNIT_ASSERT(!normalStopReceived);
+ if (error) {
+ errorStopReceived = true;
+ }
+ else {
+ normalStopReceived = true;
+ }
+ }
+
+ private:
+ DummyEventLoop* eventLoop;
+ boost::shared_ptr<FakeDNSSDQuerier> querier;
+ std::vector<LinkLocalService> addedServices;
+ std::vector<LinkLocalService> changedServices;
+ std::vector<LinkLocalService> removedServices;
+ std::vector<DNSSDServiceID> registeredServices;
+ DNSSDServiceID* aliceServiceID;
+ DNSSDResolveServiceQuery::Result* aliceServiceInfo;
+ DNSSDServiceID* testServiceID;
+ DNSSDResolveServiceQuery::Result* testServiceInfo;
+ DNSSDResolveServiceQuery::Result* testServiceInfo2;
+ bool errorStopReceived;
+ bool normalStopReceived;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceBrowserTest);
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp
index b850f14..b5d7ef5 100644
--- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp
+++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp
@@ -10,11 +10,10 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testGetTXTRecord);
CPPUNIT_TEST(testCreateFromTXTRecord);
CPPUNIT_TEST(testCreateFromTXTRecord_InvalidSize);
+ CPPUNIT_TEST(testGetTXTRecordCreateFromTXTRecord_RoundTrip);
CPPUNIT_TEST_SUITE_END();
public:
- LinkLocalServiceInfoTest() {}
-
void testGetTXTRecord() {
LinkLocalServiceInfo info;
info.setFirstName("Remko");
@@ -37,6 +36,28 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(String("a"), info.getLastName());
}
+
+ void testGetTXTRecordCreateFromTXTRecord_RoundTrip() {
+ LinkLocalServiceInfo info;
+ info.setFirstName("Remko");
+ info.setLastName("Tron\xc3\xe7on");
+ info.setEMail("remko-email@swift.im");
+ info.setJID(JID("remko-jid@swift.im"));
+ info.setMessage("I'm busy");
+ info.setNick("el-tramo");
+ info.setStatus(LinkLocalServiceInfo::DND);
+ info.setPort(1234);
+
+ LinkLocalServiceInfo info2 = LinkLocalServiceInfo::createFromTXTRecord(info.toTXTRecord());
+ CPPUNIT_ASSERT_EQUAL(info.getFirstName(), info2.getFirstName());
+ CPPUNIT_ASSERT_EQUAL(info.getLastName(), info2.getLastName());
+ CPPUNIT_ASSERT_EQUAL(info.getEMail(), info2.getEMail());
+ CPPUNIT_ASSERT_EQUAL(info.getJID(), info2.getJID());
+ CPPUNIT_ASSERT_EQUAL(info.getMessage(), info2.getMessage());
+ CPPUNIT_ASSERT_EQUAL(info.getNick(), info2.getNick());
+ CPPUNIT_ASSERT(info.getStatus() == info2.getStatus());
+ CPPUNIT_ASSERT(info.getPort() == info2.getPort());
+ }
};
CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceInfoTest);
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp
new file mode 100644
index 0000000..69ec718
--- /dev/null
+++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp
@@ -0,0 +1,62 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/LinkLocal/LinkLocalService.h"
+
+using namespace Swift;
+
+class LinkLocalServiceTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(LinkLocalServiceTest);
+ CPPUNIT_TEST(testGetDescription_WithNick);
+ CPPUNIT_TEST(testGetDescription_WithFirstName);
+ CPPUNIT_TEST(testGetDescription_WithLastName);
+ CPPUNIT_TEST(testGetDescription_WithFirstAndLastName);
+ CPPUNIT_TEST(testGetDescription_NoInfo);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testGetDescription_WithNick() {
+ LinkLocalService testling = createService("alice@wonderland", "Alice", "Alice In", "Wonderland");
+
+ CPPUNIT_ASSERT_EQUAL(String("Alice"), testling.getDescription());
+ }
+
+ void testGetDescription_WithFirstName() {
+ LinkLocalService testling = createService("alice@wonderland", "", "Alice In");
+
+ CPPUNIT_ASSERT_EQUAL(String("Alice In"), testling.getDescription());
+ }
+
+ void testGetDescription_WithLastName() {
+ LinkLocalService testling = createService("alice@wonderland", "", "", "Wonderland");
+
+ CPPUNIT_ASSERT_EQUAL(String("Wonderland"), testling.getDescription());
+ }
+
+ void testGetDescription_WithFirstAndLastName() {
+ LinkLocalService testling = createService("alice@wonderland", "", "Alice In", "Wonderland");
+
+ CPPUNIT_ASSERT_EQUAL(String("Alice In Wonderland"), testling.getDescription());
+ }
+
+ void testGetDescription_NoInfo() {
+ LinkLocalService testling = createService("alice@wonderland");
+
+ CPPUNIT_ASSERT_EQUAL(String("alice@wonderland"), testling.getDescription());
+ }
+
+ private:
+ LinkLocalService createService(const String& name, const String& nickName = String(), const String& firstName = String(), const String& lastName = String()) {
+ DNSSDServiceID service(name, "local.");
+ LinkLocalServiceInfo info;
+ info.setFirstName(firstName);
+ info.setLastName(lastName);
+ info.setNick(nickName);
+ return LinkLocalService(service,
+ DNSSDResolveServiceQuery::Result(
+ name + "._presence._tcp.local", "rabbithole.local", 1234,
+ info.toTXTRecord()));
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceTest);
diff --git a/Swiften/LinkLocal/UnitTest/Makefile.inc b/Swiften/LinkLocal/UnitTest/Makefile.inc
index abc1180..e5f1bf0 100644
--- a/Swiften/LinkLocal/UnitTest/Makefile.inc
+++ b/Swiften/LinkLocal/UnitTest/Makefile.inc
@@ -1,2 +1,4 @@
UNITTEST_SOURCES += \
+ Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp \
+ Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp \
Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp