diff options
-rw-r--r-- | Swiften/Network/UnboundDomainNameResolver.cpp | 164 | ||||
-rw-r--r-- | Swiften/Network/UnboundDomainNameResolver.h | 32 |
2 files changed, 109 insertions, 87 deletions
diff --git a/Swiften/Network/UnboundDomainNameResolver.cpp b/Swiften/Network/UnboundDomainNameResolver.cpp index 1b36012..698a99a 100644 --- a/Swiften/Network/UnboundDomainNameResolver.cpp +++ b/Swiften/Network/UnboundDomainNameResolver.cpp @@ -1,73 +1,54 @@ +/* + * Copyright (c) 2012 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + #include "UnboundDomainNameResolver.h" #include <vector> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/enable_shared_from_this.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) { - - } +struct UnboundWrapperHelper { + UnboundWrapperHelper(UnboundDomainNameResolver* resolver, boost::shared_ptr<UnboundQuery> query) : resolver(resolver), query(query) {} + UnboundDomainNameResolver* resolver; + boost::shared_ptr<UnboundQuery> query; +}; - virtual ~UnboundDomainNameServiceQuery() { - if (ubContext) { - ub_ctx_delete(ubContext); - } +class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameServiceQuery> { + public: + UnboundDomainNameServiceQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { } - static void unbound_service_callback(void* data, int err, struct ub_result* result) { - UnboundDomainNameServiceQuery* query = static_cast<UnboundDomainNameServiceQuery*>(data); - query->handleResult(err, result); - } + virtual ~UnboundDomainNameServiceQuery() { } virtual void run() { int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); - /* 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); + helper, UnboundDomainNameResolver::unbound_callback_wrapper, 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(); + delete helper; } } @@ -86,7 +67,7 @@ class UnboundDomainNameServiceQuery : public DomainNameServiceQuery { 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)) { + (ldns_rr_rd_count(rr) != 4)) { continue; } @@ -97,8 +78,8 @@ class UnboundDomainNameServiceQuery : public DomainNameServiceQuery { 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)) { + (ldns_buffer_position(buffer) < 2) || + !ldns_buffer_reserve(buffer, 1)) { // either name invalid, empty or buffer to small continue; } @@ -120,60 +101,26 @@ class UnboundDomainNameServiceQuery : public DomainNameServiceQuery { } private: - TimerFactory* timerFactory; - Timer::ref timer; std::string name; - ub_ctx* ubContext; }; -class UnboundDomainNameAddressQuery : public DomainNameAddressQuery { +class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameAddressQuery> { public: - UnboundDomainNameAddressQuery(TimerFactory* timerFactory, const std::string& name) : timerFactory(timerFactory), name(name), ubContext(0) { - + UnboundDomainNameAddressQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { } - 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 ~UnboundDomainNameAddressQuery() { } virtual void run() { int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); - /* 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); + helper, UnboundDomainNameResolver::unbound_callback_wrapper, 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(); + delete helper; } } @@ -197,25 +144,68 @@ class UnboundDomainNameAddressQuery : public DomainNameAddressQuery { } private: - TimerFactory* timerFactory; - Timer::ref timer; std::string name; - ub_ctx* ubContext; - }; UnboundDomainNameResolver::UnboundDomainNameResolver(EventLoop* eventLoop, TimerFactory* timerFactory) : eventLoop(eventLoop), timerFactory(timerFactory) { + ubContext = ub_ctx_create(); + if(!ubContext) { + SWIFT_LOG(debug) << "could not create unbound context" << std::endl; + } + + ub_ctx_async(ubContext, true); + + int ret; + + /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */ + if( (ret=ub_ctx_resolvconf(ubContext, const_cast<char*>("/etc/resolv.conf"))) != 0) { + SWIFT_LOG(debug) << "error reading resolv.conf: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + /* read /etc/hosts for locally supplied host addresses */ + if( (ret=ub_ctx_hosts(ubContext, const_cast<char*>("/etc/hosts"))) != 0) { + SWIFT_LOG(debug) << "error reading hosts: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + + // FIXME: use boost's asio to get notified about unbound's fd readability + timer = timerFactory->createTimer(1000); + timer->onTick.connect(boost::bind(&UnboundDomainNameResolver::processData, this)); + timer->start(); + } UnboundDomainNameResolver::~UnboundDomainNameResolver() { + if (ubContext) { + ub_ctx_delete(ubContext); + } +} + +void UnboundDomainNameResolver::unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result) { + query->handleResult(err, result); +} + +void UnboundDomainNameResolver::unbound_callback_wrapper(void* data, int err, ub_result* result) { + UnboundWrapperHelper* helper = static_cast<UnboundWrapperHelper*>(data); + UnboundDomainNameResolver* resolver = helper->resolver; + resolver->unbound_callback(helper->query, err, result); + delete helper; +} + +void UnboundDomainNameResolver::processData() { + if (ub_poll(ubContext)) { + int ret = ub_process(ubContext); + if(ret != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; + } + } + timer->start(); } boost::shared_ptr<DomainNameServiceQuery> UnboundDomainNameResolver::createServiceQuery(const std::string& name) { - return boost::make_shared<UnboundDomainNameServiceQuery>(timerFactory, name); + return boost::make_shared<UnboundDomainNameServiceQuery>(this, ubContext, name); } boost::shared_ptr<DomainNameAddressQuery> UnboundDomainNameResolver::createAddressQuery(const std::string& name) { - return boost::make_shared<UnboundDomainNameAddressQuery>(timerFactory, name); + return boost::make_shared<UnboundDomainNameAddressQuery>(this, ubContext, name); } } diff --git a/Swiften/Network/UnboundDomainNameResolver.h b/Swiften/Network/UnboundDomainNameResolver.h index 37cf2f6..cd0b167 100644 --- a/Swiften/Network/UnboundDomainNameResolver.h +++ b/Swiften/Network/UnboundDomainNameResolver.h @@ -1,11 +1,34 @@ +/* + * Copyright (c) 2012 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + #pragma once #include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/Timer.h> + +#include <boost/shared_ptr.hpp> + +#include <unbound.h> namespace Swift { class EventLoop; class TimerFactory; + class UnboundDomainNameResolver; + + class UnboundQuery { + public: + UnboundQuery(UnboundDomainNameResolver* resolver, ub_ctx* context) : resolver(resolver), ubContext(context) {} + virtual ~UnboundQuery() {} + virtual void handleResult(int err, ub_result* result) = 0; + protected: + UnboundDomainNameResolver* resolver; + ub_ctx* ubContext; + }; + class UnboundDomainNameResolver : public DomainNameResolver { public: UnboundDomainNameResolver(EventLoop* eventLoop, TimerFactory* timerFactory); @@ -14,9 +37,18 @@ namespace Swift { virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name); virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); + static void unbound_callback_wrapper(void* data, int err, ub_result* result); + + private: + void unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result); + + void processData(); + private: EventLoop* eventLoop; TimerFactory* timerFactory; + ub_ctx* ubContext; + Timer::ref timer; }; } |