summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/LinkLocal')
-rw-r--r--Swiften/LinkLocal/BonjourBrowseQuery.h55
-rw-r--r--Swiften/LinkLocal/BonjourQuerier.cpp115
-rw-r--r--Swiften/LinkLocal/BonjourQuerier.h45
-rw-r--r--Swiften/LinkLocal/BonjourQuery.cpp31
-rw-r--r--Swiften/LinkLocal/BonjourQuery.h28
-rw-r--r--Swiften/LinkLocal/DNSSDBrowseQuery.cpp8
-rw-r--r--Swiften/LinkLocal/DNSSDBrowseQuery.h15
-rw-r--r--Swiften/LinkLocal/Makefile.inc3
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 \