From 0a7336577f9609c70bb4d846c668e7853746cb52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Wed, 22 Jul 2009 23:36:52 +0200
Subject: Started LinkLocalServiceBrowser.


diff --git a/Swiften/LinkLocal/AppleDNSSDService.cpp b/Swiften/LinkLocal/AppleDNSSDService.cpp
index 5262357..bf66e50 100644
--- a/Swiften/LinkLocal/AppleDNSSDService.cpp
+++ b/Swiften/LinkLocal/AppleDNSSDService.cpp
@@ -268,8 +268,6 @@ void AppleDNSSDService::handleServiceResolvedGlobal(DNSServiceRef sdRef, DNSServ
 
 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) {
diff --git a/Swiften/LinkLocal/LinkLocalService.h b/Swiften/LinkLocal/LinkLocalService.h
new file mode 100644
index 0000000..446feb8
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalService.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "Swiften/Base/String.h"
+#include "Swiften/Network/HostAddress.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+
+namespace Swift {
+	class LinkLocalService {
+		public:
+			LinkLocalService();
+
+			const String& getName() const {
+				return name;
+			}
+
+			void setName(const String& n) {
+				name = n;
+			}
+
+			const String& getHostname() const {
+				return hostname;
+			}
+
+			void setHostname(const String& h) {
+				hostname = h;
+			}
+
+			const HostAddress& getAddress() const {
+				return address;
+			}
+
+			void setAddress(const HostAddress& a) {
+				address = a;
+			}
+
+			const LinkLocalServiceInfo& getInfo() const {
+				return info;
+			}
+
+			void setInfo(const LinkLocalServiceInfo& i) {
+				info = i;
+			}
+
+		private:
+			String name;
+			String hostname;
+			LinkLocalServiceInfo info;
+			HostAddress address;
+	};
+}
diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp
new file mode 100644
index 0000000..63cf075
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp
@@ -0,0 +1,38 @@
+#include <boost/bind.hpp>
+#include <iostream>
+
+#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h"
+#include "Swiften/Network/HostAddress.h"
+
+namespace Swift {
+
+LinkLocalServiceBrowser::LinkLocalServiceBrowser(boost::shared_ptr<DNSSDService> service) : dnsSDService(service) {
+	dnsSDService->onServiceAdded.connect(
+			boost::bind(&LinkLocalServiceBrowser::handleServiceAdded, this, _1));
+	dnsSDService->onServiceRemoved.connect(
+			boost::bind(&LinkLocalServiceBrowser::handleServiceRemoved, this, _1));
+	dnsSDService->onServiceResolved.connect(
+			boost::bind(&LinkLocalServiceBrowser::handleServiceResolved, this, _1, _2));
+}
+
+void LinkLocalServiceBrowser::handleServiceAdded(const LinkLocalServiceID& service) {
+	dnsSDService->startResolvingService(service);
+}
+
+void LinkLocalServiceBrowser::handleServiceRemoved(const LinkLocalServiceID& service) {
+	/*dnsSDService->stopResolvingService(service);
+	services.erase(service);*/
+}
+
+void LinkLocalServiceBrowser::handleServiceResolved(const LinkLocalServiceID& service, const DNSSDService::ResolveResult& result) {
+	std::pair<ServiceMap::iterator, bool> r = services.insert(std::make_pair(service, result));
+	if (r.second) {
+		onServiceAdded(service);
+	}
+	else {
+		onServiceChanged(service);
+	}
+}
+
+
+}
diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h
new file mode 100644
index 0000000..c0788e6
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include <map>
+#include <vector>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/LinkLocal/DNSSDService.h"
+#include "Swiften/LinkLocal/LinkLocalService.h"
+
+namespace Swift {
+	class HostAddress;
+
+	class LinkLocalServiceBrowser {
+		public:
+			LinkLocalServiceBrowser(boost::shared_ptr<DNSSDService> service);
+
+			boost::signal<void (const LinkLocalServiceID&)> onServiceAdded;
+			boost::signal<void (const LinkLocalServiceID&)> onServiceChanged;
+
+		private:
+			void handleServiceAdded(const LinkLocalServiceID&);
+			void handleServiceRemoved(const LinkLocalServiceID&);
+			void handleServiceResolved(const LinkLocalServiceID& service, const DNSSDService::ResolveResult& result);
+
+		private:
+			boost::shared_ptr<DNSSDService> dnsSDService;
+			typedef std::map<LinkLocalServiceID, DNSSDService::ResolveResult> ServiceMap;
+			ServiceMap services;
+	};
+}
diff --git a/Swiften/LinkLocal/LinkLocalServiceID.cpp b/Swiften/LinkLocal/LinkLocalServiceID.cpp
new file mode 100644
index 0000000..4248d88
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalServiceID.cpp
@@ -0,0 +1,7 @@
+#include "Swiften/LinkLocal/LinkLocalServiceID.h"
+
+namespace Swift {
+
+const String LinkLocalServiceID::PresenceServiceType = String("_presence._tcp");
+
+}
diff --git a/Swiften/LinkLocal/LinkLocalServiceID.h b/Swiften/LinkLocal/LinkLocalServiceID.h
index 72615d4..ca5ba17 100644
--- a/Swiften/LinkLocal/LinkLocalServiceID.h
+++ b/Swiften/LinkLocal/LinkLocalServiceID.h
@@ -5,10 +5,12 @@
 namespace Swift {
 	class LinkLocalServiceID {
 		public:
+			static const String PresenceServiceType;
+
 			LinkLocalServiceID(
 				const String& name, 
 				const String& type, 
-				const String& domain, 
+				const String& domain = PresenceServiceType, 
 				int networkInterface = 0) : 
 					name(name), 
 					type(type), 
diff --git a/Swiften/LinkLocal/Makefile.inc b/Swiften/LinkLocal/Makefile.inc
index 788c000..a890d0a 100644
--- a/Swiften/LinkLocal/Makefile.inc
+++ b/Swiften/LinkLocal/Makefile.inc
@@ -1,7 +1,9 @@
 SWIFTEN_SOURCES += \
 	Swiften/LinkLocal/DNSSDService.cpp \
 	Swiften/LinkLocal/LinkLocalRoster.cpp \
+	Swiften/LinkLocal/LinkLocalServiceID.cpp \
 	Swiften/LinkLocal/LinkLocalServiceInfo.cpp \
+	Swiften/LinkLocal/LinkLocalServiceBrowser.cpp \
 	Swiften/LinkLocal/IncomingLinkLocalSession.cpp \
 	Swiften/LinkLocal/OutgoingLinkLocalSession.cpp \
 	Swiften/LinkLocal/LinkLocalConnector.cpp
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp
new file mode 100644
index 0000000..449a823
--- /dev/null
+++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp
@@ -0,0 +1,95 @@
+#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/UnitTest/MockDNSSDService.h"
+#include "Swiften/LinkLocal/DNSSDService.h"
+#include "Swiften/EventLoop/DummyEventLoop.h"
+
+// Test IP address change
+
+using namespace Swift;
+
+class LinkLocalServiceBrowserTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(LinkLocalServiceBrowserTest);
+		CPPUNIT_TEST(testServiceAdded);
+		CPPUNIT_TEST(testServiceAdded_NoServiceInfo);
+		CPPUNIT_TEST(testServiceChanged);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		LinkLocalServiceBrowserTest() {}
+
+		void setUp() {
+			eventLoop = new DummyEventLoop();
+			dnsSDService = boost::shared_ptr<MockDNSSDService>(new MockDNSSDService());
+			testServiceID = new LinkLocalServiceID("foo", "bar.local");
+			testServiceInfo = new DNSSDService::ResolveResult("xmpp.bar.local", 1234, LinkLocalServiceInfo());
+			testServiceInfo2 = new DNSSDService::ResolveResult("xmpp.foo.local", 2345, LinkLocalServiceInfo());
+		}
+
+		void tearDown() {
+			delete testServiceInfo2;
+			delete testServiceInfo;
+			delete testServiceID;
+			delete eventLoop;
+		}
+
+		void testServiceAdded() {
+			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+
+			dnsSDService->setServiceInfo(*testServiceID,*testServiceInfo);
+			dnsSDService->addService(*testServiceID);
+			eventLoop->processEvents();
+
+			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size()));
+			CPPUNIT_ASSERT(addedServices[0] == *testServiceID);
+			// TODO: Check getServices
+		}
+
+		void testServiceAdded_NoServiceInfo() {
+			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+
+			dnsSDService->addService(*testServiceID);
+			eventLoop->processEvents();
+
+			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(addedServices.size()));
+		}
+
+		void testServiceChanged() {
+			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+			dnsSDService->setServiceInfo(*testServiceID,*testServiceInfo);
+			dnsSDService->addService(*testServiceID);
+			eventLoop->processEvents();
+
+			dnsSDService->setServiceInfo(*testServiceID,*testServiceInfo2);
+			eventLoop->processEvents();
+			// TODO: Check getServices
+		}
+
+	private:
+		boost::shared_ptr<LinkLocalServiceBrowser> createTestling() {
+			boost::shared_ptr<LinkLocalServiceBrowser> testling(
+					new LinkLocalServiceBrowser(dnsSDService));
+			testling->onServiceAdded.connect(boost::bind(
+					&LinkLocalServiceBrowserTest::handleServiceAdded, this, _1));
+			return testling;
+		}
+
+		void handleServiceAdded(const LinkLocalServiceID& service) {
+			addedServices.push_back(service);
+		}
+
+	private:
+		DummyEventLoop* eventLoop;
+		boost::shared_ptr<MockDNSSDService> dnsSDService;
+		std::vector<LinkLocalServiceID> addedServices;
+		LinkLocalServiceID* testServiceID;
+		DNSSDService::ResolveResult* testServiceInfo;
+		DNSSDService::ResolveResult* 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
new file mode 100644
index 0000000..5d857fb
--- /dev/null
+++ b/Swiften/LinkLocal/UnitTest/MockDNSSDService.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <vector>
+#include <map>
+#include <boost/bind.hpp>
+
+#include "Swiften/EventLoop/MainEventLoop.h"
+#include "Swiften/LinkLocal/DNSSDService.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 setServiceInfo(const LinkLocalServiceID& id, const DNSSDService::ResolveResult& info) {
+				serviceInfo.insert(std::make_pair(id, 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;
+	};
+
+
+}
-- 
cgit v0.10.2-6-g49f6