summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/LinkLocal/BonjourQuerier.cpp')
-rw-r--r--Swiften/LinkLocal/BonjourQuerier.cpp115
1 files changed, 115 insertions, 0 deletions
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());
+ }
+ }
+ }
+ }
+}
+
+}