diff options
Diffstat (limited to 'Swiften/LinkLocal')
22 files changed, 551 insertions, 151 deletions
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h index 62d8606..8e3181e 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h @@ -14,14 +14,17 @@ namespace Swift { &sdRef, 0, 0, "_presence._tcp", 0, &BonjourBrowseQuery::handleServiceDiscoveredStatic, this); if (result != kDNSServiceErr_NoError) { - std::cout << "Error" << std::endl; - // TODO + sdRef = NULL; } } void startBrowsing() { - assert(sdRef); - run(); + if (!sdRef) { + MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this()); + } + else { + run(); + } } void stopBrowsing() { @@ -35,7 +38,7 @@ namespace Swift { void handleServiceDiscovered(DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *name, const char *type, const char *domain) { if (errorCode != kDNSServiceErr_NoError) { - return; + MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this()); } else { DNSSDServiceID service(name, type, domain, interfaceIndex); diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp index c065d4d..70fbc7c 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp @@ -22,7 +22,7 @@ BonjourQuerier::BonjourQuerier() : stopRequested(false), thread(0) { } BonjourQuerier::~BonjourQuerier() { - stop(); + assert(!thread); } boost::shared_ptr<DNSSDBrowseQuery> BonjourQuerier::createBrowseQuery() { @@ -64,18 +64,19 @@ void BonjourQuerier::interruptSelect() { } void BonjourQuerier::start() { - stop(); + assert(!thread); thread = new boost::thread(boost::bind(&BonjourQuerier::run, shared_from_this())); } void BonjourQuerier::stop() { if (thread) { stopRequested = true; - runningQueries.clear(); // TODO: Is this the right thing to do? + assert(runningQueries.empty()); runningQueriesAvailableEvent.notify_one(); interruptSelect(); thread->join(); delete thread; + thread = NULL; stopRequested = false; } } diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h index 9c4db13..41e5831 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h @@ -18,13 +18,21 @@ namespace Swift { txtRecord.getSize(), txtRecord.getData(), &BonjourRegisterQuery::handleServiceRegisteredStatic, this); if (result != kDNSServiceErr_NoError) { - // TODO - std::cerr << "Error creating service registration" << std::endl; + sdRef = NULL; } } void registerService() { - run(); + if (sdRef) { + run(); + } + else { + MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); + } + } + + void unregisterService() { + stop(); } void updateServiceInfo(const LinkLocalServiceInfo& info) { diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h index 58c6588..6e2a852 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h @@ -19,13 +19,18 @@ namespace Swift { hostname.getUTF8Data(), &BonjourResolveHostnameQuery::handleHostnameResolvedStatic, this); if (result != kDNSServiceErr_NoError) { - MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>()), shared_from_this()); + sdRef = NULL; } } //void DNSSDResolveHostnameQuery::run() { void run() { - BonjourQuery::run(); + if (sdRef) { + BonjourQuery::run(); + } + else { + MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>()), shared_from_this()); + } } private: diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h index 1ebd487..8b3f7ec 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h @@ -18,12 +18,17 @@ namespace Swift { service.getDomain().getUTF8Data(), &BonjourResolveServiceQuery::handleServiceResolvedStatic, this); if (result != kDNSServiceErr_NoError) { - MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); + sdRef = NULL; } } void start() { - run(); + if (sdRef) { + run(); + } + else { + MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); + } } void stop() { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h index 86967ed..9b30858 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h @@ -14,5 +14,6 @@ namespace Swift { boost::signal<void (const DNSSDServiceID&)> onServiceAdded; boost::signal<void (const DNSSDServiceID&)> onServiceRemoved; + boost::signal<void ()> onError; }; } diff --git a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h index a643880..627cc6b 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h @@ -13,6 +13,7 @@ namespace Swift { virtual ~DNSSDRegisterQuery(); virtual void registerService() = 0; + virtual void unregisterService() = 0; virtual void updateServiceInfo(const LinkLocalServiceInfo& info) = 0; boost::signal<void (boost::optional<DNSSDServiceID>)> onRegisterFinished; 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..222500a --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp @@ -0,0 +1,92 @@ +#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() { +} + +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 LinkLocalServiceInfo& 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()); + } + } + } +} + +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()); + } + } +} + +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..6c5f343 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h @@ -0,0 +1,61 @@ +#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 LinkLocalServiceInfo; + class FakeDNSSDQuery; + class FakeDNSSDBrowseQuery; + + class FakeDNSSDQuerier : + public DNSSDQuerier, + public EventOwner, + public boost::enable_shared_from_this<FakeDNSSDQuerier> { + public: + FakeDNSSDQuerier(); + + boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); + boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( + const String& name, int port, const LinkLocalServiceInfo& 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); + + 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: + 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..b4646fd --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include "Swiften/Base/String.h" + +namespace Swift { + class FakeDNSSDQuerier; + + class FakeDNSSDRegisterQuery : public DNSSDRegisterQuery, public FakeDNSSDQuery { + public: + FakeDNSSDRegisterQuery(const String& name, int port, const LinkLocalServiceInfo& info, boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), name(name), port(port), info(info) { + } + + void registerService() { + run(); + } + + void updateServiceInfo(const LinkLocalServiceInfo&) { + } + + void unregisterService() { + finish(); + } + + String name; + int port; + LinkLocalServiceInfo info; + }; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h new file mode 100644 index 0000000..2ff84d3 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h @@ -0,0 +1,25 @@ +#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(); + } + + 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 index 8612fee..3d2c969 100644 --- a/Swiften/LinkLocal/DNSSD/Makefile.inc +++ b/Swiften/LinkLocal/DNSSD/Makefile.inc @@ -11,3 +11,5 @@ include Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc endif ifeq ($(HAVE_AVAHI),yes) endif + +include Swiften/LinkLocal/DNSSD/Fake/Makefile.inc diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp index 4e9c2de..aed917a 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp @@ -7,17 +7,66 @@ namespace Swift { -LinkLocalServiceBrowser::LinkLocalServiceBrowser(boost::shared_ptr<DNSSDQuerier> querier) : querier(querier) { +LinkLocalServiceBrowser::LinkLocalServiceBrowser(boost::shared_ptr<DNSSDQuerier> querier) : querier(querier), haveError(false) { +} + +LinkLocalServiceBrowser::~LinkLocalServiceBrowser() { + assert(!isRunning()); +} + + +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(); } -LinkLocalServiceBrowser::~LinkLocalServiceBrowser() { +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); + registerQuery->onRegisterFinished.connect( + boost::bind(&LinkLocalServiceBrowser::handleRegisterFinished, this, _1)); + registerQuery->registerService(); +} + +void LinkLocalServiceBrowser::unregisterService() { + assert(registerQuery); + registerQuery->unregisterService(); + registerQuery.reset(); } std::vector<LinkLocalService> LinkLocalServiceBrowser::getServices() const { @@ -44,6 +93,7 @@ void LinkLocalServiceBrowser::handleServiceRemoved(const DNSSDServiceID& service assert(i != resolveQueries.end()); i->second->stop(); resolveQueries.erase(i); + services.erase(service); onServiceRemoved(service); } @@ -60,4 +110,16 @@ void LinkLocalServiceBrowser::handleServiceResolved(const DNSSDServiceID& servic } } +void LinkLocalServiceBrowser::handleRegisterFinished(const boost::optional<DNSSDServiceID>& result) { + if (!result) { + haveError = true; + stop(); + } +} + +void LinkLocalServiceBrowser::handleBrowseError() { + haveError = true; + stop(); +} + } diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h index 7ec796a..33c9858 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.h +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h @@ -9,8 +9,10 @@ #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 { @@ -18,23 +20,37 @@ namespace Swift { 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 unregisterService(); + bool isRegistered() const; + std::vector<LinkLocalService> getServices() const; boost::signal<void (const DNSSDServiceID&)> onServiceAdded; boost::signal<void (const DNSSDServiceID&)> onServiceChanged; boost::signal<void (const DNSSDServiceID&)> onServiceRemoved; + 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::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/UnitTest/LinkLocalServiceBrowserTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp index 34f797c..7e2dd26 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp @@ -5,20 +5,26 @@ #include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" #include "Swiften/LinkLocal/LinkLocalService.h" -#include "Swiften/LinkLocal/UnitTest/MockDNSSDService.h" -#include "Swiften/LinkLocal/DNSSDService.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" -// Test canCreate() == false - 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(testServiceChanged); CPPUNIT_TEST(testServiceRemoved); + CPPUNIT_TEST(testError_BrowseErrorAfterStart); + CPPUNIT_TEST(testError_BrowseErrorAfterResolve); + CPPUNIT_TEST(testRegisterService); + CPPUNIT_TEST(testRegisterService_Error); + CPPUNIT_TEST(testRegisterService_Reregister); CPPUNIT_TEST_SUITE_END(); public: @@ -26,10 +32,10 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { void setUp() { eventLoop = new DummyEventLoop(); - dnsSDServiceFactory = new MockDNSSDServiceFactory(); - testServiceID = new LinkLocalServiceID("foo", "bar.local"); - testServiceInfo = new DNSSDService::ResolveResult("xmpp.bar.local", 1234, LinkLocalServiceInfo()); - testServiceInfo2 = new DNSSDService::ResolveResult("xmpp.foo.local", 2345, LinkLocalServiceInfo()); + querier = boost::shared_ptr<FakeDNSSDQuerier>(new FakeDNSSDQuerier()); + testServiceID = new DNSSDServiceID("foo", "bar.local"); + testServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.bar.local", "xmpp.bar.local", 1234, LinkLocalServiceInfo()); + testServiceInfo2 = new DNSSDResolveServiceQuery::Result("_presence.tcp.bar.local", "xmpp.foo.local", 2345, LinkLocalServiceInfo()); } void tearDown() { @@ -40,15 +46,33 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { delete testServiceInfo2; delete testServiceInfo; delete testServiceID; - delete dnsSDServiceFactory; 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(); - dnsSDService()->setServiceInfo(*testServiceID,*testServiceInfo); - dnsSDService()->addService(*testServiceID); + querier->setServiceInfo(*testServiceID,*testServiceInfo); + querier->addService(*testServiceID); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size())); @@ -60,26 +84,33 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { 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(); - dnsSDService()->addService(*testServiceID); + querier->addService(*testServiceID); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(addedServices.size())); std::vector<LinkLocalService> services = testling->getServices(); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(services.size())); + + testling->stop(); } void testServiceChanged() { boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); - dnsSDService()->setServiceInfo(*testServiceID,*testServiceInfo); - dnsSDService()->addService(*testServiceID); + testling->start(); + querier->setServiceInfo(*testServiceID,*testServiceInfo); + querier->addService(*testServiceID); eventLoop->processEvents(); - dnsSDService()->setServiceInfo(*testServiceID,*testServiceInfo2); + querier->setServiceInfo(*testServiceID,*testServiceInfo2); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size())); @@ -91,31 +122,93 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { 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(); - dnsSDService()->setServiceInfo(*testServiceID,*testServiceInfo); - dnsSDService()->addService(*testServiceID); + testling->start(); + querier->setServiceInfo(*testServiceID,*testServiceInfo); + querier->addService(*testServiceID); eventLoop->processEvents(); - dnsSDService()->removeService(*testServiceID); + querier->removeService(*testServiceID); eventLoop->processEvents(); - dnsSDService()->setServiceInfo(*testServiceID,*testServiceInfo2); + 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] == *testServiceID); - std::vector<LinkLocalService> services = testling->getServices(); - CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(services.size())); + 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()); + } + + 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())); + } + + void testRegisterService() { + boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); + testling->start(); + eventLoop->processEvents(); + + testling->stop(); + } + + void testRegisterService_Error() { + boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); + testling->start(); + testling->registerService("", 1234); + eventLoop->processEvents(); + + querier->setRegisterError(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(!testling->isRunning()); + CPPUNIT_ASSERT(testling->hasError()); + } + + void testRegisterService_Reregister() { + boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); + testling->start(); + eventLoop->processEvents(); + + testling->stop(); } private: boost::shared_ptr<LinkLocalServiceBrowser> createTestling() { boost::shared_ptr<LinkLocalServiceBrowser> testling( - new LinkLocalServiceBrowser(dnsSDServiceFactory)); + new LinkLocalServiceBrowser(querier)); testling->onServiceAdded.connect(boost::bind( &LinkLocalServiceBrowserTest::handleServiceAdded, this, _1)); testling->onServiceChanged.connect(boost::bind( @@ -125,32 +218,27 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { return testling; } - void handleServiceAdded(const LinkLocalServiceID& service) { + void handleServiceAdded(const DNSSDServiceID& service) { addedServices.push_back(service); } - void handleServiceRemoved(const LinkLocalServiceID& service) { + void handleServiceRemoved(const DNSSDServiceID& service) { removedServices.push_back(service); } - void handleServiceChanged(const LinkLocalServiceID& service) { + void handleServiceChanged(const DNSSDServiceID& service) { changedServices.push_back(service); } - boost::shared_ptr<MockDNSSDService> dnsSDService() const { - CPPUNIT_ASSERT(dnsSDServiceFactory->services.size() > 0); - return dnsSDServiceFactory->services[0]; - } - private: DummyEventLoop* eventLoop; - MockDNSSDServiceFactory* dnsSDServiceFactory; - std::vector<LinkLocalServiceID> addedServices; - std::vector<LinkLocalServiceID> changedServices; - std::vector<LinkLocalServiceID> removedServices; - LinkLocalServiceID* testServiceID; - DNSSDService::ResolveResult* testServiceInfo; - DNSSDService::ResolveResult* testServiceInfo2; + boost::shared_ptr<FakeDNSSDQuerier> querier; + std::vector<DNSSDServiceID> addedServices; + std::vector<DNSSDServiceID> changedServices; + std::vector<DNSSDServiceID> removedServices; + DNSSDServiceID* testServiceID; + DNSSDResolveServiceQuery::Result* testServiceInfo; + DNSSDResolveServiceQuery::Result* testServiceInfo2; }; CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceBrowserTest); diff --git a/Swiften/LinkLocal/UnitTest/Makefile.inc b/Swiften/LinkLocal/UnitTest/Makefile.inc index abc1180..9640fa7 100644 --- a/Swiften/LinkLocal/UnitTest/Makefile.inc +++ b/Swiften/LinkLocal/UnitTest/Makefile.inc @@ -1,2 +1,3 @@ UNITTEST_SOURCES += \ + Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp \ Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp diff --git a/Swiften/LinkLocal/UnitTest/MockDNSSDService.h b/Swiften/LinkLocal/UnitTest/MockDNSSDService.h deleted file mode 100644 index 69ac06d..0000000 --- a/Swiften/LinkLocal/UnitTest/MockDNSSDService.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include <vector> -#include <map> -#include <boost/bind.hpp> - -#include "Swiften/EventLoop/MainEventLoop.h" -#include "Swiften/LinkLocal/DNSSDService.h" -#include "Swiften/LinkLocal/DNSSDServiceFactory.h" - -namespace Swift { - class MockDNSSDService : public DNSSDService { - public: - MockDNSSDService() { - } - - void start() { - } - - void stop() { - } - - virtual void registerService(const String&, int, const LinkLocalServiceInfo&) { - assert(false); - } - - virtual void updateService(const LinkLocalServiceInfo&) { - assert(false); - } - - virtual void unregisterService() { - assert(false); - } - - virtual void startResolvingService(const LinkLocalServiceID& id) { - resolvingServices.push_back(id); - broadcastServiceInfo(id); - } - - virtual void stopResolvingService(const LinkLocalServiceID& id) { - resolvingServices.erase(std::remove(resolvingServices.begin(), resolvingServices.end(), id), resolvingServices.end()); - } - - virtual void resolveHostname(const String&, int) { - assert(false); - } - - void addService(const LinkLocalServiceID& id) { - MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), id)); - } - - void removeService(const LinkLocalServiceID& id) { - serviceInfo.erase(id); - MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRemoved), id)); - } - - void setServiceInfo(const LinkLocalServiceID& id, const DNSSDService::ResolveResult& info) { - std::pair<ServiceInfoMap::iterator, bool> r = serviceInfo.insert(std::make_pair(id, info)); - if (!r.second) { - r.first->second = info; - } - broadcastServiceInfo(id); - } - - private: - void broadcastServiceInfo(const LinkLocalServiceID& id) { - if (std::find(resolvingServices.begin(), resolvingServices.end(), id) != resolvingServices.end()) { - ServiceInfoMap::const_iterator i = serviceInfo.find(id); - if (i != serviceInfo.end()) { - MainEventLoop::postEvent( - boost::bind(boost::ref(onServiceResolved), id, i->second)); - } - } - } - - private: - typedef std::map<LinkLocalServiceID,DNSSDService::ResolveResult> ServiceInfoMap; - ServiceInfoMap serviceInfo; - std::vector<LinkLocalServiceID> resolvingServices; - }; - - class MockDNSSDServiceFactory : public DNSSDServiceFactory { - public: - boost::shared_ptr<DNSSDService> createDNSSDService() { - boost::shared_ptr<MockDNSSDService> result(new MockDNSSDService()); - services.push_back(result); - return result; - } - - bool canCreate() const { - return true; - } - - std::vector<boost::shared_ptr<MockDNSSDService> > services; - }; - -} |