From d3ade7a21cf2cc5e394eccca302e20360052a164 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 24 Apr 2010 18:58:52 +0200
Subject: Don't lookup duplicate discovered link-local services.

This fixes a segfault due to the old query being deleted when a
duplicate query is started.

diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
index 0ef8c74..d8e7acf 100644
--- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
@@ -43,6 +43,7 @@ boost::shared_ptr<DNSSDResolveHostnameQuery> FakeDNSSDQuerier::createResolveHost
 
 void FakeDNSSDQuerier::addRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) {
 	runningQueries.push_back(query);
+	allQueriesEverRun.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());
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
index 7ff092d..ef7af02 100644
--- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
@@ -54,6 +54,18 @@ namespace Swift {
 			void setBrowseError();
 			void setRegisterError();
 
+		public:
+			template<typename T>
+			std::vector< boost::shared_ptr<T> > getAllQueriesEverRun() const {
+				std::vector< boost::shared_ptr<T> > result;
+				foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, allQueriesEverRun) {
+					if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) {
+						result.push_back(resultQuery);
+					}
+				}
+				return result;
+			}
+
 		private:
 			template<typename T>
 			std::vector< boost::shared_ptr<T> > getQueries() const {
@@ -69,6 +81,7 @@ namespace Swift {
 		private:
 			String domain;
 			std::list< boost::shared_ptr<FakeDNSSDQuery> > runningQueries;
+			std::list< boost::shared_ptr<FakeDNSSDQuery> > allQueriesEverRun;
 			std::set<DNSSDServiceID> services;
 			typedef std::map<DNSSDServiceID,DNSSDResolveServiceQuery::Result> ServiceInfoMap;
 			ServiceInfoMap serviceInfo;
diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp
index f865807..efd56e3 100644
--- a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp
+++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp
@@ -95,14 +95,16 @@ void LinkLocalServiceBrowser::handleServiceAdded(const DNSSDServiceID& service)
 	if (selfService && service == *selfService) {
 		return;
 	}
-	boost::shared_ptr<DNSSDResolveServiceQuery> resolveQuery = querier->createResolveServiceQuery(service);
-	resolveQuery->onServiceResolved.connect(
-		boost::bind(&LinkLocalServiceBrowser::handleServiceResolved, this, service, _1));
-	std::pair<ResolveQueryMap::iterator, bool> r = resolveQueries.insert(std::make_pair(service, resolveQuery));
-	if (!r.second) {
+
+	std::pair<ResolveQueryMap::iterator, bool> r = resolveQueries.insert(std::make_pair(service, boost::shared_ptr<DNSSDResolveServiceQuery>()));
+	if (r.second) {
+		// There was no existing query yet. Start a new query.
+		boost::shared_ptr<DNSSDResolveServiceQuery> resolveQuery = querier->createResolveServiceQuery(service);
+		resolveQuery->onServiceResolved.connect(
+			boost::bind(&LinkLocalServiceBrowser::handleServiceResolved, this, service, _1));
 		r.first->second = resolveQuery;
+		resolveQuery->start();
 	}
-	resolveQuery->start();
 }
 
 void LinkLocalServiceBrowser::handleServiceRemoved(const DNSSDServiceID& service) {
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp
index f754d50..4f53931 100644
--- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp
+++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp
@@ -14,6 +14,7 @@
 #include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
 #include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
 #include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h"
 #include "Swiften/EventLoop/DummyEventLoop.h"
 
 using namespace Swift;
@@ -26,6 +27,7 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST(testServiceAdded_NoServiceInfo);
 		CPPUNIT_TEST(testServiceAdded_RegisteredService);
 		CPPUNIT_TEST(testServiceAdded_UnregisteredService);
+		CPPUNIT_TEST(testServiceAdded_Twice);
 		CPPUNIT_TEST(testServiceChanged);
 		CPPUNIT_TEST(testServiceRemoved);
 		CPPUNIT_TEST(testServiceRemoved_UnregisteredService);
@@ -178,6 +180,31 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture {
 			testling->stop();
 		}
 
+		void testServiceAdded_Twice() {
+			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
+			testling->start();
+			eventLoop->processEvents();
+
+			querier->setServiceInfo(*testServiceID,*testServiceInfo);
+			querier->addService(*testServiceID);
+			querier->addService(*testServiceID);
+			eventLoop->processEvents();
+
+			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(querier->getAllQueriesEverRun<FakeDNSSDResolveServiceQuery>().size()));
+			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size()));
+			CPPUNIT_ASSERT(addedServices[0].getID() == *testServiceID);
+			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size()));
+			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size()));
+			std::vector<LinkLocalService> services = testling->getServices();
+			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(services.size()));
+			CPPUNIT_ASSERT(*testServiceID == services[0].getID());
+			CPPUNIT_ASSERT(testServiceInfo->port == services[0].getPort());
+			CPPUNIT_ASSERT(testServiceInfo->host == services[0].getHostname());
+
+			testling->stop();
+		}
+
+
 		void testServiceChanged() {
 			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling();
 			testling->start();
-- 
cgit v0.10.2-6-g49f6