From 714e831bb9ea2b14cba3c2696c12e2e13b1bb9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Thu, 23 Jul 2009 21:04:08 +0200 Subject: Add beginning of new DNS-SD query framework. diff --git a/Slimber/Server.cpp b/Slimber/Server.cpp index ba55403..c3c3d22 100644 --- a/Slimber/Server.cpp +++ b/Slimber/Server.cpp @@ -69,9 +69,9 @@ void Server::handleNewLinkLocalConnection(boost::shared_ptr connecti registerLinkLocalSession(session); } -void Server::handleServiceRegistered(const DNSSDService::Service& service) { - std::cout << "Service registered " << service.name << " " << service.type << " " << service.domain << std::endl; - selfJID_ = JID(service.name); +void Server::handleServiceRegistered(const LinkLocalServiceID& service) { + std::cout << "Service registered " << service.getName() << " " << service.getType() << " " << service.getDomain() << std::endl; + selfJID_ = JID(service.getName()); } void Server::handleSessionStarted() { diff --git a/Slimber/Server.h b/Slimber/Server.h index ac80509..b40f576 100644 --- a/Slimber/Server.h +++ b/Slimber/Server.h @@ -33,7 +33,7 @@ namespace Swift { private: void handleNewClientConnection(boost::shared_ptr c); void handleNewLinkLocalConnection(boost::shared_ptr connection); - void handleServiceRegistered(const DNSSDService::Service& service); + void handleServiceRegistered(const LinkLocalServiceID& service); void handleSessionStarted(); void handleSessionFinished(boost::shared_ptr); void handleLinkLocalSessionFinished(boost::shared_ptr session); 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 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(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 +#include +#include +#include + +#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 BonjourQuerier::createBrowseQuery() { + return boost::shared_ptr(new BonjourBrowseQuery(shared_from_this())); +} + +void BonjourQuerier::addRunningQuery(boost::shared_ptr query) { + { + boost::lock_guard lock(runningQueriesMutex); + runningQueries.push_back(query); + } + runningQueriesAvailableEvent.notify_one(); + interruptSelect(); +} + +void BonjourQuerier::removeRunningQuery(boost::shared_ptr query) { + { + boost::lock_guard 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 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& 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 lock(runningQueriesMutex); + foreach(const boost::shared_ptr& 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 +#include +#include +#include +#include + +#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, + public EventOwner { + public: + BonjourQuerier(); + ~BonjourQuerier(); + + boost::shared_ptr createBrowseQuery(); + + void start(); + void stop(); + + private: + friend class BonjourQuery; + + void addRunningQuery(boost::shared_ptr); + void removeRunningQuery(boost::shared_ptr); + + private: + void interruptSelect(); + void run(); + + private: + bool stopRequested; + boost::thread* thread; + boost::mutex runningQueriesMutex; + std::list< boost::shared_ptr > 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 q) : querier(q), sdRef(0) { +} + +BonjourQuery::~BonjourQuery() { + DNSServiceRefDeallocate(sdRef); +} + +void BonjourQuery::processResult() { + boost::lock_guard lock(sdRefMutex); + DNSServiceProcessResult(sdRef); +} + +int BonjourQuery::getSocketID() const { + boost::lock_guard 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 +#include +#include +#include + +namespace Swift { + class BonjourQuerier; + + class BonjourQuery : public boost::enable_shared_from_this { + public: + BonjourQuery(boost::shared_ptr); + virtual ~BonjourQuery(); + + void processResult(); + int getSocketID() const; + + protected: + void run(); + void finish(); + + protected: + boost::shared_ptr 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 + +#include "Swiften/LinkLocal/LinkLocalServiceID.h" + +namespace Swift { + class DNSSDBrowseQuery { + public: + virtual ~DNSSDBrowseQuery(); + + boost::signal onServiceAdded; + boost::signal 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 \ -- cgit v0.10.2-6-g49f6