From 714e831bb9ea2b14cba3c2696c12e2e13b1bb9d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
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<Connection> 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<Connection> c);
 			void handleNewLinkLocalConnection(boost::shared_ptr<Connection> connection);
-			void handleServiceRegistered(const DNSSDService::Service& service);
+			void handleServiceRegistered(const LinkLocalServiceID& service);
 			void handleSessionStarted();
 			void handleSessionFinished(boost::shared_ptr<ServerFromClientSession>);
 			void handleLinkLocalSessionFinished(boost::shared_ptr<Session> 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<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 \
-- 
cgit v0.10.2-6-g49f6