summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2009-12-04 21:49:44 (GMT)
committerRemko Tronçon <git@el-tramo.be>2009-12-04 23:52:36 (GMT)
commit897ad55ffee76c9e84ffb174d700f6182a3e7d0b (patch)
treef31e6bd601cf5f1483a3f4ad5e79a492d3a9ca3e /Swiften/Network
parentc8802e3bef6b73d349a711b187c72aea0a3dd964 (diff)
downloadswift-897ad55ffee76c9e84ffb174d700f6182a3e7d0b.zip
swift-897ad55ffee76c9e84ffb174d700f6182a3e7d0b.tar.bz2
Implemented CAresDomainNameResolver.
Diffstat (limited to 'Swiften/Network')
-rw-r--r--Swiften/Network/CAresDomainNameResolver.cpp159
-rw-r--r--Swiften/Network/CAresDomainNameResolver.h34
-rw-r--r--Swiften/Network/DomainNameResolver.cpp14
-rw-r--r--Swiften/Network/DomainNameResolver.h5
-rw-r--r--Swiften/Network/DomainNameServiceQuery.h6
-rw-r--r--Swiften/Network/PlatformDomainNameResolver.cpp12
-rw-r--r--Swiften/Network/PlatformDomainNameServiceQuery.cpp10
-rw-r--r--Swiften/Network/SConscript4
8 files changed, 222 insertions, 22 deletions
diff --git a/Swiften/Network/CAresDomainNameResolver.cpp b/Swiften/Network/CAresDomainNameResolver.cpp
new file mode 100644
index 0000000..6daba3d
--- /dev/null
+++ b/Swiften/Network/CAresDomainNameResolver.cpp
@@ -0,0 +1,159 @@
+// TODO: Check the second param of postEvent. We sometimes omit it. Same
+// goes for the PlatformDomainNameResolver.
+
+#include "Swiften/Network/CAresDomainNameResolver.h"
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <algorithm>
+
+#include "Swiften/Network/DomainNameServiceQuery.h"
+#include "Swiften/Network/DomainNameAddressQuery.h"
+#include "Swiften/Base/ByteArray.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+#include "Swiften/Base/foreach.h"
+
+namespace Swift {
+
+class CAresQuery : public boost::enable_shared_from_this<CAresQuery>, public EventOwner {
+ public:
+ CAresQuery(const String& query, int dnsclass, int type, CAresDomainNameResolver* resolver) : query(query), dnsclass(dnsclass), type(type), resolver(resolver) {
+ }
+
+ virtual ~CAresQuery() {
+ }
+
+ void addToQueue() {
+ resolver->addToQueue(shared_from_this());
+ }
+
+ void doRun(ares_channel* channel) {
+ ares_query(*channel, query.getUTF8Data(), dnsclass, type, &CAresQuery::handleResult, this);
+ }
+
+ static void handleResult(void* arg, int status, int timeouts, unsigned char* buffer, int len) {
+ reinterpret_cast<CAresQuery*>(arg)->handleResult(status, timeouts, buffer, len);
+ }
+
+ virtual void handleResult(int status, int, unsigned char* buffer, int len) = 0;
+
+ private:
+ String query;
+ int dnsclass;
+ int type;
+ CAresDomainNameResolver* resolver;
+};
+
+class CAresDomainNameServiceQuery : public DomainNameServiceQuery, public CAresQuery {
+ public:
+ CAresDomainNameServiceQuery(const String& service, CAresDomainNameResolver* resolver) : CAresQuery(service, 1, 33, resolver) {
+ }
+
+ virtual void run() {
+ addToQueue();
+ }
+
+ void handleResult(int status, int, unsigned char* buffer, int len) {
+ if (status == ARES_SUCCESS) {
+ std::vector<DomainNameServiceQuery::Result> records;
+ ares_srv_reply* rawRecords;
+ if (ares_parse_srv_reply(buffer, len, &rawRecords) == ARES_SUCCESS) {
+ for( ; rawRecords != NULL; rawRecords = rawRecords->next) {
+ DomainNameServiceQuery::Result record;
+ record.priority = rawRecords->priority;
+ record.weight = rawRecords->weight;
+ record.port = rawRecords->port;
+ record.hostname = String(rawRecords->host);
+ records.push_back(record);
+ }
+ }
+ std::sort(records.begin(), records.end(), ResultPriorityComparator());
+ MainEventLoop::postEvent(boost::bind(boost::ref(onResult), records));
+ }
+ else if (status != ARES_EDESTRUCTION) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onResult), std::vector<DomainNameServiceQuery::Result>()), shared_from_this());
+ }
+ }
+};
+
+class CAresDomainNameAddressQuery : public DomainNameAddressQuery, public CAresQuery {
+ public:
+ CAresDomainNameAddressQuery(const String& host, CAresDomainNameResolver* resolver) : CAresQuery(host, 1, 1, resolver) {
+ }
+
+ virtual void run() {
+ addToQueue();
+ }
+
+ void handleResult(int status, int, unsigned char* buffer, int len) {
+ if (status == ARES_SUCCESS) {
+ struct hostent* hosts;
+ if (ares_parse_a_reply(buffer, len, &hosts, NULL, NULL) == ARES_SUCCESS) {
+ // Check whether the different fields are what we expect them to be
+ struct in_addr addr;
+ addr.s_addr = *(unsigned int*)hosts->h_addr_list[0];
+ HostAddress result(inet_ntoa(addr));
+ MainEventLoop::postEvent(boost::bind(boost::ref(onResult), result, boost::optional<DomainNameResolveError>()), boost::dynamic_pointer_cast<CAresDomainNameAddressQuery>(shared_from_this()));
+ ares_free_hostent(hosts);
+ }
+ else {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onResult), HostAddress(), boost::optional<DomainNameResolveError>(DomainNameResolveError())), shared_from_this());
+ }
+ }
+ else if (status != ARES_EDESTRUCTION) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onResult), HostAddress(), boost::optional<DomainNameResolveError>(DomainNameResolveError())), shared_from_this());
+ }
+ }
+};
+
+CAresDomainNameResolver::CAresDomainNameResolver() : stopRequested(false) {
+ ares_init(&channel);
+ thread = new boost::thread(boost::bind(&CAresDomainNameResolver::run, this));
+}
+
+CAresDomainNameResolver::~CAresDomainNameResolver() {
+ stopRequested = true;
+ thread->join();
+ ares_destroy(channel);
+}
+
+boost::shared_ptr<DomainNameServiceQuery> CAresDomainNameResolver::createServiceQuery(const String& name) {
+ return boost::shared_ptr<DomainNameServiceQuery>(new CAresDomainNameServiceQuery(getNormalized(name), this));
+}
+
+boost::shared_ptr<DomainNameAddressQuery> CAresDomainNameResolver::createAddressQuery(const String& name) {
+ return boost::shared_ptr<DomainNameAddressQuery>(new CAresDomainNameAddressQuery(getNormalized(name), this));
+}
+
+void CAresDomainNameResolver::addToQueue(boost::shared_ptr<CAresQuery> query) {
+ boost::lock_guard<boost::mutex> lock(pendingQueriesMutex);
+ pendingQueries.push_back(query);
+}
+
+void CAresDomainNameResolver::run() {
+ fd_set readers, writers;
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+ while(!stopRequested) {
+ {
+ boost::unique_lock<boost::mutex> lock(pendingQueriesMutex);
+ foreach(const boost::shared_ptr<CAresQuery>& query, pendingQueries) {
+ query->doRun(&channel);
+ }
+ pendingQueries.clear();
+ }
+ FD_ZERO(&readers);
+ FD_ZERO(&writers);
+ int nfds = ares_fds(channel, &readers, &writers);
+ //if (nfds) {
+ // break;
+ //}
+ struct timeval tv;
+ struct timeval* tvp = ares_timeout(channel, &timeout, &tv);
+ select(nfds, &readers, &writers, NULL, tvp);
+ ares_process(channel, &readers, &writers);
+ }
+}
+
+}
diff --git a/Swiften/Network/CAresDomainNameResolver.h b/Swiften/Network/CAresDomainNameResolver.h
new file mode 100644
index 0000000..0cdd163
--- /dev/null
+++ b/Swiften/Network/CAresDomainNameResolver.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <ares.h>
+#include <boost/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <list>
+
+#include "Swiften/Network/DomainNameResolver.h"
+
+namespace Swift {
+ class CAresQuery;
+
+ class CAresDomainNameResolver : public DomainNameResolver {
+ public:
+ CAresDomainNameResolver();
+ ~CAresDomainNameResolver();
+
+ virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const String& name);
+ virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const String& name);
+
+ private:
+ friend class CAresQuery;
+
+ void run();
+ void addToQueue(boost::shared_ptr<CAresQuery>);
+
+ private:
+ bool stopRequested;
+ ares_channel channel;
+ boost::thread* thread;
+ boost::mutex pendingQueriesMutex;
+ std::list< boost::shared_ptr<CAresQuery> > pendingQueries;
+ };
+}
diff --git a/Swiften/Network/DomainNameResolver.cpp b/Swiften/Network/DomainNameResolver.cpp
index 907dfc9..63ed881 100644
--- a/Swiften/Network/DomainNameResolver.cpp
+++ b/Swiften/Network/DomainNameResolver.cpp
@@ -1,8 +1,22 @@
#include "Swiften/Network/DomainNameResolver.h"
+#include <idna.h>
+
namespace Swift {
DomainNameResolver::~DomainNameResolver() {
}
+String DomainNameResolver::getNormalized(const String& domain) {
+ char* output;
+ if (idna_to_ascii_8z(domain.getUTF8Data(), &output, 0) == IDNA_SUCCESS) {
+ String result(output);
+ free(output);
+ return result;
+ }
+ else {
+ return domain;
+ }
+}
+
}
diff --git a/Swiften/Network/DomainNameResolver.h b/Swiften/Network/DomainNameResolver.h
index b99ace3..d3dab26 100644
--- a/Swiften/Network/DomainNameResolver.h
+++ b/Swiften/Network/DomainNameResolver.h
@@ -2,6 +2,8 @@
#include <boost/shared_ptr.hpp>
+#include "Swiften/Base/String.h"
+
namespace Swift {
class DomainNameServiceQuery;
class DomainNameAddressQuery;
@@ -13,5 +15,8 @@ namespace Swift {
virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const String& name) = 0;
virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const String& name) = 0;
+
+ protected:
+ static String getNormalized(const String& domain);
};
}
diff --git a/Swiften/Network/DomainNameServiceQuery.h b/Swiften/Network/DomainNameServiceQuery.h
index 3c08749..57e48d3 100644
--- a/Swiften/Network/DomainNameServiceQuery.h
+++ b/Swiften/Network/DomainNameServiceQuery.h
@@ -18,6 +18,12 @@ namespace Swift {
int weight;
};
+ struct ResultPriorityComparator {
+ bool operator()(const DomainNameServiceQuery::Result& a, const DomainNameServiceQuery::Result& b) const {
+ return a.priority < b.priority;
+ }
+ };
+
virtual ~DomainNameServiceQuery();
virtual void run() = 0;
diff --git a/Swiften/Network/PlatformDomainNameResolver.cpp b/Swiften/Network/PlatformDomainNameResolver.cpp
index 755b177..5ffa2fb 100644
--- a/Swiften/Network/PlatformDomainNameResolver.cpp
+++ b/Swiften/Network/PlatformDomainNameResolver.cpp
@@ -9,7 +9,6 @@
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/enable_shared_from_this.hpp>
-#include <idna.h>
#include <algorithm>
#include "Swiften/Base/String.h"
@@ -77,17 +76,6 @@ namespace {
bool safeToJoin;
};
- String getNormalized(const String& domain) {
- char* output;
- if (idna_to_ascii_8z(domain.getUTF8Data(), &output, 0) == IDNA_SUCCESS) {
- String result(output);
- free(output);
- return result;
- }
- else {
- return domain;
- }
- }
}
namespace Swift {
diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.cpp b/Swiften/Network/PlatformDomainNameServiceQuery.cpp
index d6c87dc..659f397 100644
--- a/Swiften/Network/PlatformDomainNameServiceQuery.cpp
+++ b/Swiften/Network/PlatformDomainNameServiceQuery.cpp
@@ -22,14 +22,6 @@
using namespace Swift;
-namespace {
- struct SRVRecordPriorityComparator {
- bool operator()(const DomainNameServiceQuery::Result& a, const DomainNameServiceQuery::Result& b) const {
- return a.priority < b.priority;
- }
- };
-}
-
namespace Swift {
PlatformDomainNameServiceQuery::PlatformDomainNameServiceQuery(const String& service) : thread(NULL), service(service), safeToJoin(true) {
@@ -165,7 +157,7 @@ void PlatformDomainNameServiceQuery::doRun() {
#endif
safeToJoin = true;
- std::sort(records.begin(), records.end(), SRVRecordPriorityComparator());
+ std::sort(records.begin(), records.end(), ResultPriorityComparator());
std::cout << "Sending out " << records.size() << " SRV results " << std::endl;
MainEventLoop::postEvent(boost::bind(boost::ref(onResult), records));
}
diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript
index 9aa8139..d63b673 100644
--- a/Swiften/Network/SConscript
+++ b/Swiften/Network/SConscript
@@ -1,7 +1,8 @@
Import("swiften_env")
myenv = swiften_env.Clone()
-myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"])
+myenv.MergeFlags(myenv["LIBIDN_FLAGS"])
+myenv.MergeFlags(myenv["CARES_FLAGS"])
objects = myenv.StaticObject([
"BoostConnection.cpp",
@@ -19,6 +20,7 @@ objects = myenv.StaticObject([
"DomainNameServiceQuery.cpp",
"PlatformDomainNameResolver.cpp",
"PlatformDomainNameServiceQuery.cpp",
+ "CAresDomainNameResolver.cpp",
"StaticDomainNameResolver.cpp",
"HostAddress.cpp",
"Timer.cpp",