diff options
Diffstat (limited to 'Swiften/LinkLocal')
-rw-r--r-- | Swiften/LinkLocal/BonjourBrowseQuery.h | 55 | ||||
-rw-r--r-- | Swiften/LinkLocal/BonjourQuerier.cpp | 115 | ||||
-rw-r--r-- | Swiften/LinkLocal/BonjourQuerier.h | 45 | ||||
-rw-r--r-- | Swiften/LinkLocal/BonjourQuery.cpp | 31 | ||||
-rw-r--r-- | Swiften/LinkLocal/BonjourQuery.h | 28 | ||||
-rw-r--r-- | Swiften/LinkLocal/DNSSDBrowseQuery.cpp | 8 | ||||
-rw-r--r-- | Swiften/LinkLocal/DNSSDBrowseQuery.h | 15 | ||||
-rw-r--r-- | Swiften/LinkLocal/Makefile.inc | 3 |
8 files changed, 300 insertions, 0 deletions
diff --git a/Swiften/LinkLocal/BonjourBrowseQuery.h b/Swiften/LinkLocal/BonjourBrowseQuery.h new file mode 100644 index 0000000..5b14d30 --- /dev/null +++ b/Swiften/LinkLocal/BonjourBrowseQuery.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Swiften/LinkLocal/BonjourQuery.h" +#include "Swiften/LinkLocal/DNSSDBrowseQuery.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::handleServiceDiscoveredGlobal , this); + if (result != kDNSServiceErr_NoError) { + // TODO + } + } + + void startBrowsing() { + assert(sdRef); + run(); + } + + void stopBrowsing() { + finish(); + } + + private: + static void handleServiceDiscoveredGlobal(DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) { + static_cast<BonjourBrowseQuery*>(context)->handleServiceDiscovered(flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain); + } + + void handleServiceDiscovered( + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *serviceName, + const char *type, + const char *domain) { + if (errorCode != kDNSServiceErr_NoError) { + return; + } + else { + LinkLocalServiceID service(serviceName, type, domain, interfaceIndex); + if (flags & kDNSServiceFlagsAdd) { + onServiceAdded(service); + } + else { + onServiceRemoved(service); + } + } + } + }; +} diff --git a/Swiften/LinkLocal/BonjourQuerier.cpp b/Swiften/LinkLocal/BonjourQuerier.cpp new file mode 100644 index 0000000..1ddbd9d --- /dev/null +++ b/Swiften/LinkLocal/BonjourQuerier.cpp @@ -0,0 +1,115 @@ +#include "Swiften/LinkLocal/BonjourQuerier.h" + +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <fcntl.h> + +#include "Swiften/EventLoop/MainEventLoop.h" +#include "Swiften/LinkLocal/BonjourBrowseQuery.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]; + // TODO: Schedule thread +} + +BonjourQuerier::~BonjourQuerier() { + stop(); +} + +boost::shared_ptr<DNSSDBrowseQuery> BonjourQuerier::createBrowseQuery() { + return boost::shared_ptr<DNSSDBrowseQuery>(new BonjourBrowseQuery(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() { + stop(); + 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? + runningQueriesAvailableEvent.notify_one(); + interruptSelect(); + thread->join(); + delete thread; + stopRequested = false; + } +} + +void BonjourQuerier::run() { + while (!stopRequested) { + fd_set fdSet; + int maxSocket; + { + boost::unique_lock<boost::mutex> lock(runningQueriesMutex); + runningQueriesAvailableEvent.wait(lock); + if (runningQueries.empty()) { + continue; + } + + // Run all running queries + FD_ZERO(&fdSet); + int 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(const boost::shared_ptr<BonjourQuery>& query, runningQueries) { + if (FD_ISSET(query->getSocketID(), &fdSet)) { + MainEventLoop::postEvent( + boost::bind(&BonjourQuery::processResult, query), shared_from_this()); + } + } + } + } +} + +} diff --git a/Swiften/LinkLocal/BonjourQuerier.h b/Swiften/LinkLocal/BonjourQuerier.h new file mode 100644 index 0000000..037d9e6 --- /dev/null +++ b/Swiften/LinkLocal/BonjourQuerier.h @@ -0,0 +1,45 @@ +#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/EventLoop/EventOwner.h" +#include "Swiften/LinkLocal/DNSSDBrowseQuery.h" +#include "Swiften/LinkLocal/BonjourQuery.h" + +namespace Swift { + class BonjourQuerier : + public boost::enable_shared_from_this<BonjourQuerier>, + public EventOwner { + public: + BonjourQuerier(); + ~BonjourQuerier(); + + boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); + + void start(); + void stop(); + + private: + friend class BonjourQuery; + + void addRunningQuery(boost::shared_ptr<BonjourQuery>); + void removeRunningQuery(boost::shared_ptr<BonjourQuery>); + + private: + 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/BonjourQuery.cpp b/Swiften/LinkLocal/BonjourQuery.cpp new file mode 100644 index 0000000..a9c13fb --- /dev/null +++ b/Swiften/LinkLocal/BonjourQuery.cpp @@ -0,0 +1,31 @@ +#include "Swiften/LinkLocal/BonjourQuery.h" +#include "Swiften/LinkLocal/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/BonjourQuery.h b/Swiften/LinkLocal/BonjourQuery.h new file mode 100644 index 0000000..2a47f73 --- /dev/null +++ b/Swiften/LinkLocal/BonjourQuery.h @@ -0,0 +1,28 @@ +#pragma once + +#include <dns_sd.h> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/thread/mutex.hpp> + +namespace Swift { + class BonjourQuerier; + + class BonjourQuery : 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/DNSSDBrowseQuery.cpp b/Swiften/LinkLocal/DNSSDBrowseQuery.cpp new file mode 100644 index 0000000..4924247 --- /dev/null +++ b/Swiften/LinkLocal/DNSSDBrowseQuery.cpp @@ -0,0 +1,8 @@ +#include "Swiften/LinkLocal/DNSSDBrowseQuery.h" + +namespace Swift { + +DNSSDBrowseQuery::~DNSSDBrowseQuery() { +} + +} diff --git a/Swiften/LinkLocal/DNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSDBrowseQuery.h new file mode 100644 index 0000000..b46d968 --- /dev/null +++ b/Swiften/LinkLocal/DNSSDBrowseQuery.h @@ -0,0 +1,15 @@ +#pragma once + +#include <boost/signal.hpp> + +#include "Swiften/LinkLocal/LinkLocalServiceID.h" + +namespace Swift { + class DNSSDBrowseQuery { + public: + virtual ~DNSSDBrowseQuery(); + + boost::signal<void (const LinkLocalServiceID&)> onServiceAdded; + boost::signal<void (const LinkLocalServiceID&)> onServiceRemoved; + }; +} diff --git a/Swiften/LinkLocal/Makefile.inc b/Swiften/LinkLocal/Makefile.inc index 4bd1b0e..b43a7e4 100644 --- a/Swiften/LinkLocal/Makefile.inc +++ b/Swiften/LinkLocal/Makefile.inc @@ -1,5 +1,8 @@ SWIFTEN_SOURCES += \ + Swiften/LinkLocal/BonjourQuery.cpp \ + Swiften/LinkLocal/DNSSDBrowseQuery.cpp \ Swiften/LinkLocal/DNSSDServiceFactory.cpp \ + Swiften/LinkLocal/BonjourQuerier.cpp \ Swiften/LinkLocal/PlatformDNSSDServiceFactory.cpp \ Swiften/LinkLocal/DNSSDService.cpp \ Swiften/LinkLocal/LinkLocalRoster.cpp \ |