diff options
Diffstat (limited to 'Swiften/LinkLocal/BonjourQuerier.cpp')
-rw-r--r-- | Swiften/LinkLocal/BonjourQuerier.cpp | 115 |
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()); + } + } + } + } +} + +} |