diff options
Diffstat (limited to 'Swiften')
-rw-r--r-- | Swiften/Network/BoostNetworkFactories.cpp | 5 | ||||
-rw-r--r-- | Swiften/Network/SConscript | 9 | ||||
-rw-r--r-- | Swiften/Network/UnboundDomainNameResolver.cpp | 221 | ||||
-rw-r--r-- | Swiften/Network/UnboundDomainNameResolver.h | 22 | ||||
-rw-r--r-- | Swiften/SConscript | 3 |
5 files changed, 258 insertions, 2 deletions
diff --git a/Swiften/Network/BoostNetworkFactories.cpp b/Swiften/Network/BoostNetworkFactories.cpp index 488e519..091a70a 100644 --- a/Swiften/Network/BoostNetworkFactories.cpp +++ b/Swiften/Network/BoostNetworkFactories.cpp @@ -15,12 +15,15 @@ #include <Swiften/TLS/PlatformTLSFactories.h> #include <Swiften/Network/PlatformProxyProvider.h> +#include <Swiften/Network/UnboundDomainNameResolver.h> + namespace Swift { BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(eventLoop){ timerFactory = new BoostTimerFactory(ioServiceThread.getIOService(), eventLoop); connectionFactory = new BoostConnectionFactory(ioServiceThread.getIOService(), eventLoop); - domainNameResolver = new PlatformDomainNameResolver(eventLoop); + domainNameResolver = new UnboundDomainNameResolver(eventLoop, timerFactory); + //domainNameResolver = new PlatformDomainNameResolver(eventLoop); connectionServerFactory = new BoostConnectionServerFactory(ioServiceThread.getIOService(), eventLoop); #ifdef SWIFT_EXPERIMENTAL_FT natTraverser = new PlatformNATTraversalWorker(eventLoop); diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index 0d0abbd..429ca51 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -5,6 +5,10 @@ myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) if myenv.get("HAVE_CARES", False) : myenv.MergeFlags(myenv.get("CARES_FLAGS", {})) +if myenv.get("unbound", False) : + myenv.MergeFlags(myenv.get("UNBOUND_FLAGS", {})) + myenv.MergeFlags(myenv.get("LDNS_FLAGS", {})) + sourceList = [ "HTTPConnectProxiedConnection.cpp", "HTTPConnectProxiedConnectionFactory.cpp", @@ -17,7 +21,7 @@ sourceList = [ "BoostIOServiceThread.cpp", "BOSHConnection.cpp", "BOSHConnectionPool.cpp", - "CachingNameOnlyDomainNameResolver.cpp", + "CachingNameOnlyDomainNameResolver.cpp", "ConnectionFactory.cpp", "ConnectionServer.cpp", "ConnectionServerFactory.cpp", @@ -57,6 +61,9 @@ sourceList = [ if myenv.get("HAVE_CARES", False) : sourceList.append("CAresDomainNameResolver.cpp") + +if myenv.get("unbound", False) : + sourceList.append("UnboundDomainNameResolver.cpp") if myenv["PLATFORM"] == "darwin" : myenv.Append(FRAMEWORKS = ["CoreServices", "SystemConfiguration"]) diff --git a/Swiften/Network/UnboundDomainNameResolver.cpp b/Swiften/Network/UnboundDomainNameResolver.cpp new file mode 100644 index 0000000..1b36012 --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.cpp @@ -0,0 +1,221 @@ +#include "UnboundDomainNameResolver.h" + +#include <vector> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/DomainNameResolveError.h> +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/Network/TimerFactory.h> + + +#include <arpa/inet.h> +#include <ldns/ldns.h> +#include <unbound.h> +#include <unistd.h> + +namespace Swift { + +class UnboundDomainNameServiceQuery : public DomainNameServiceQuery { + public: + UnboundDomainNameServiceQuery(TimerFactory* timerFactory, const std::string& name) : timerFactory(timerFactory), name(name), ubContext(0) { + + } + + virtual ~UnboundDomainNameServiceQuery() { + if (ubContext) { + ub_ctx_delete(ubContext); + } + } + + static void unbound_service_callback(void* data, int err, struct ub_result* result) { + UnboundDomainNameServiceQuery* query = static_cast<UnboundDomainNameServiceQuery*>(data); + query->handleResult(err, result); + } + + virtual void run() { + int retval; + + /* create context */ + ubContext = ub_ctx_create(); + if(!ubContext) { + SWIFT_LOG(debug) << "could not create unbound context" << std::endl; + return; + } + ub_ctx_async(ubContext, true); + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_SRV, + 1 /* CLASS IN (internet) */, + this, unbound_service_callback, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + } + + timer = timerFactory->createTimer(500); + timer->onTick.connect(boost::bind(&UnboundDomainNameServiceQuery::processData, this)); + timer->start(); + } + + void processData() { + if (ub_poll(ubContext)) { + int ret = ub_process(ubContext); + if(ret != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; + } + } else { + timer->start(); + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<DomainNameServiceQuery::Result> serviceRecords; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + } else { + if(result->havedata) { + ldns_pkt* replyPacket = 0; + ldns_buffer* buffer = ldns_buffer_new(1024); + if (buffer && ldns_wire2pkt(&replyPacket, static_cast<const uint8_t*>(result->answer_packet), result->answer_len) == LDNS_STATUS_OK) { + ldns_rr_list* rrList = ldns_pkt_answer(replyPacket); + for (size_t n = 0; n < ldns_rr_list_rr_count(rrList); n++) { + ldns_rr* rr = ldns_rr_list_rr(rrList, n); + if ((ldns_rr_get_type(rr) != LDNS_RR_TYPE_SRV) || + (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) || + (ldns_rr_rd_count(rr) != 4)) { + continue; + } + + DomainNameServiceQuery::Result serviceRecord; + serviceRecord.priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); + serviceRecord.weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1)); + serviceRecord.port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2)); + + ldns_buffer_rewind(buffer); + if ((ldns_rdf2buffer_str_dname(buffer, ldns_rr_rdf(rr, 3)) != LDNS_STATUS_OK) || + (ldns_buffer_position(buffer) < 2) || + !ldns_buffer_reserve(buffer, 1)) { + // either name invalid, empty or buffer to small + continue; + } + char terminator = 0; + ldns_buffer_write(buffer, &terminator, sizeof(terminator)); + + serviceRecord.hostname = std::string(reinterpret_cast<char*>(ldns_buffer_at(buffer, 0))); + serviceRecords.push_back(serviceRecord); + SWIFT_LOG(debug) << "hostname " << serviceRecord.hostname << " added" << std::endl; + } + } + if (replyPacket) ldns_pkt_free(replyPacket); + if (buffer) ldns_buffer_free(buffer); + } + } + + ub_resolve_free(result); + onResult(serviceRecords); + } + + private: + TimerFactory* timerFactory; + Timer::ref timer; + std::string name; + ub_ctx* ubContext; +}; + +class UnboundDomainNameAddressQuery : public DomainNameAddressQuery { + public: + UnboundDomainNameAddressQuery(TimerFactory* timerFactory, const std::string& name) : timerFactory(timerFactory), name(name), ubContext(0) { + + } + + virtual ~UnboundDomainNameAddressQuery() { + if (ubContext) { + ub_ctx_delete(ubContext); + } + } + + static void unbound_address_callback(void* data, int err, struct ub_result* result) { + UnboundDomainNameAddressQuery* query = static_cast<UnboundDomainNameAddressQuery*>(data); + query->handleResult(err, result); + } + + virtual void run() { + int retval; + + /* create context */ + ubContext = ub_ctx_create(); + if(!ubContext) { + SWIFT_LOG(debug) << "could not create unbound context" << std::endl; + return; + } + + ub_ctx_async(ubContext, true); + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_A, + 1 /* CLASS IN (internet) */, + this, unbound_address_callback, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + } + + timer = timerFactory->createTimer(500); + timer->onTick.connect(boost::bind(&UnboundDomainNameAddressQuery::processData, this)); + timer->start(); + } + + void processData() { + if (ub_poll(ubContext)) { + int ret = ub_process(ubContext); + if(ret != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; + } + } else { + timer->start(); + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<HostAddress> addresses; + boost::optional<DomainNameResolveError> error; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + error = DomainNameResolveError(); + } else { + if(result->havedata) { + for(int i=0; result->data[i]; i++) { + addresses.push_back(HostAddress(std::string(inet_ntoa(* (struct in_addr*)result->data[i])))); + } + } + } + + ub_resolve_free(result); + onResult(addresses, error); + } + + private: + TimerFactory* timerFactory; + Timer::ref timer; + std::string name; + ub_ctx* ubContext; + +}; + +UnboundDomainNameResolver::UnboundDomainNameResolver(EventLoop* eventLoop, TimerFactory* timerFactory) : eventLoop(eventLoop), timerFactory(timerFactory) { +} + +UnboundDomainNameResolver::~UnboundDomainNameResolver() { +} + +boost::shared_ptr<DomainNameServiceQuery> UnboundDomainNameResolver::createServiceQuery(const std::string& name) { + return boost::make_shared<UnboundDomainNameServiceQuery>(timerFactory, name); +} + +boost::shared_ptr<DomainNameAddressQuery> UnboundDomainNameResolver::createAddressQuery(const std::string& name) { + return boost::make_shared<UnboundDomainNameAddressQuery>(timerFactory, name); +} + +} diff --git a/Swiften/Network/UnboundDomainNameResolver.h b/Swiften/Network/UnboundDomainNameResolver.h new file mode 100644 index 0000000..37cf2f6 --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.h @@ -0,0 +1,22 @@ +#pragma once + +#include <Swiften/Network/DomainNameResolver.h> + +namespace Swift { + class EventLoop; + class TimerFactory; + + class UnboundDomainNameResolver : public DomainNameResolver { + public: + UnboundDomainNameResolver(EventLoop* eventLoop, TimerFactory* timerFactory); + virtual ~UnboundDomainNameResolver(); + + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name); + virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); + + private: + EventLoop* eventLoop; + TimerFactory* timerFactory; + }; + +} diff --git a/Swiften/SConscript b/Swiften/SConscript index c12d3b2..42c1588 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -8,6 +8,9 @@ Import("env") swiften_dep_modules = ["BOOST", "GCONF", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP"] +if env["unbound"] : + swiften_dep_modules.extend(["LDNS", "UNBOUND"]) + if env["SCONS_STAGE"] == "flags" : env["SWIFTEN_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift") version_match = re.match("(\d+)\.(\d+).*", env["SWIFTEN_VERSION"]) |