config/option/pingreplytimeoutoption.cpp
config/option/maxaddressresolutionattemptsoption.cpp
config/option/resolvedipttlthresholdoption.cpp
+ dns_neww/dnscache.cpp
+ dns_neww/dnsmaster.cpp
+ dns_neww/dnsresolver.cpp
dns/dnsresolver.cpp
dns/dnsresolverfactory.cpp
dns/hostaddress.cpp
--- /dev/null
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+
+ Christian Herdtweck, Intra2net AG 2015
+ */
+
+#include "dns_neww/dnscache.h"
+
+#include <logfunc.hpp>
+#include <boost/bind.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/asio/placeholders.hpp>
+
+using boost::bind;
+using boost::posix_time::seconds;
+using I2n::Logger::GlobalLogger;
+
+namespace Config
+{
+ int SaveTimerSeconds = 60;
+}
+
+
+
+DnsCache::DnsCache(const IoServiceItem &io_serv,
+ const std::string &cache_file)
+ : DataCache()
+ , SaveTimer( *io_serv )
+ , CacheFile( cache_file )
+ , HasChanged( false )
+{
+ // load cache from file
+ load_from_cachefile();
+
+ // schedule next save
+ (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
+ SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
+ boost::asio::placeholders::error ) );
+}
+
+
+DnsCache::~DnsCache()
+{
+ // save one last time without re-scheduling the next save
+ save_to_cachefile();
+
+ // cancel save timer
+ SaveTimer.cancel();
+}
+
+
+void DnsCache::schedule_save(const boost::system::error_code &error)
+{
+ // just in case: ensure SaveTimer is cancelled
+ SaveTimer.cancel(); // (will do nothing if already expired/cancelled)
+
+ if ( error == boost::asio::error::operation_aborted ) // cancelled
+ {
+ GlobalLogger.error() << "DNS Cache: SaveTimer was cancelled "
+ << "--> no save and no re-schedule of saving!";
+ return;
+ }
+ else if (error)
+ {
+ GlobalLogger.error() << "DNS Cache: Received error " << error
+ << " in schedule_save "
+ << "--> no save now but re-schedule saving";
+ }
+ else
+ save_to_cachefile();
+
+ // schedule next save
+ (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
+ SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
+ boost::asio::placeholders::error ) );
+}
+
+void DnsCache::save_to_cachefile()
+{
+ if (!HasChanged)
+ {
+ GlobalLogger.info() << "DNS Cache: skip saving because has not changed";
+ return;
+ }
+
+ // TODO (see trusted_net_helper, boost serialization, xml)
+ GlobalLogger.error() << "DNS Cache: Actual saving not implemented yet!";
+ HasChanged = false;
+}
+
+
+void DnsCache::load_from_cachefile()
+{
+ // TODO: some boost serialization and xml stuff, see trusted_net_helper
+ GlobalLogger.error() << "DNS Cache: Actual loading not implemented yet!";
+}
+
+/**
+ *
+ * in case the cached set is equal to the given new one, the old one is kept
+ * with TTLs updated
+ * @returns true if changed cache; returns false if new_data is same as cache
+ */
+void DnsCache::update(const std::string &hostname,
+ const HostAddressList &new_data)
+{
+ GlobalLogger.info() << "DNS Cache: update IPs for " << hostname
+ << " to " << new_data.size() << "-list";
+ DataCache[hostname] = new_data;
+ HasChanged = true;
+}
+
+
+HostAddressList DnsCache::get_data(const std::string &hostname)
+{
+ GlobalLogger.info() << "DNS Cache: request IPs for " << hostname
+ << " --> " << DataCache[hostname].size() << "-list";
+ return DataCache[hostname];
+}
+
+// (created using vim -- the world's best text editor)
+
--- /dev/null
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+
+ Christian Herdtweck, Intra2net AG 2015
+ */
+
+#ifndef DNS_CACHE_H
+#define DNS_CACHE_H
+
+#include <map>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include <boost/system/error_code.hpp>
+
+#include "host/pinger.h" // for IoserviceItem
+#include "dns/hostaddress.h"
+
+typedef std::map<std::string, HostAddressList> cache_map_type;
+
+class DnsCache
+{
+public:
+ DnsCache( const IoServiceItem &io_serv,
+ const std::string &cache_file );
+ ~DnsCache();
+
+ // accessed from ResolverBase subclasses
+ void update(const std::string &host_name, const HostAddressList &new_data);
+ HostAddressList get_data(const std::string &hostname);
+
+// variables
+private:
+ cache_map_type DataCache;
+ boost::asio::deadline_timer SaveTimer;
+ std::string CacheFile;
+ bool HasChanged;
+
+// functions
+private:
+ void schedule_save(const boost::system::error_code &error);
+ void save_to_cachefile();
+ void load_from_cachefile();
+
+};
+
+typedef boost::shared_ptr<DnsCache> DnsCacheItem;
+
+#endif
+
+// (created using vim -- the world's best text editor)
+
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio/placeholders.hpp>
+#include "dns_neww/ippseudoresolver.h"
+#include "dns_neww/dnsresolver.h"
+
using boost::bind;
using boost::posix_time::seconds;
+using boost::posix_time::minutes;
using I2n::Logger::GlobalLogger;
+
DnsMasterItem DnsMaster::TheOnlyInstance;
-void DnsMaster::create_master(const IoServiceImte &io_serv,
- const boost::ip::address &name_server,
+void DnsMaster::create_master(const IoServiceItem &io_serv,
+ const boost::asio::ip::address &name_server,
const std::string &cache_file)
{
if (TheOnlyInstance)
{
GlobalLogger.warning()
- << "Attempting to create another DnsMaster instance!";
- return false;
+ << "Blocking attempt to create another DnsMaster instance!";
+ return;
}
- TheOnlyInstance.reset( new DnsMaster(io_serv, name_server, cache_file) );
- return true;
+ GlobalLogger.info() << "Creating DNS Master";
+ DnsCacheItem cache( new DnsCache(io_serv, cache_file) );
+ TheOnlyInstance.reset( new DnsMaster(io_serv, name_server, cache) );
}
DnsMaster::DnsMaster(const IoServiceItem &io_serv,
- const boost::ip::address &name_server,
- const std::string &cache_file)
+ const boost::asio::ip::address &name_server,
+ const DnsCacheItem &cache)
: IoService( io_serv )
- , NameServer( name_server )
- , SaveTimer( *io_serv )
- , CacheFile( cache_file )
, ResolverMap()
- , DataCache()
+ , NameServer( name_server )
+ , Cache(cache)
{
- // load cache from file
- load_from_cachefile();
-
- // schedule next save
- (void) SaveTimer.expires_from_now( seconds( SaveTimerSeconds ) );
- SaveTimer.async_wait( bind( &DnsMaster::schedule_save, this,
- boost::asio::placeholders::error ) );
}
-DnsMaster::~DnsMaster()
-{
- // save one last time without re-scheduling the next save
- save_to_cachefile();
-
- // cancel save timer
- SaveTimer.cancel();
-}
-
-void DnsMaster::schedule_save(const boost::system::error_code &error)
-{
- // just in case: ensure SaveTimer is cancelled
- SaveTimer.cancel(); // (will do nothing if already expired/cancelled)
-
- if ( error == boost::asio::error::operation_aborted ) // cancelled
- {
- GlobalLogger.error() << "SaveTimer was cancelled "
- << "--> no save and no re-schedule of saving!";
- return;
- }
- else if (error)
- {
- GlobalLogger.error() << "Received error " << error
- << " in schedule_save "
- << "--> no save now but re-schedule saving";
- }
- else
- save_to_cachefile();
-
- // schedule next save
- (void) SaveTimer.expires_from_now( seconds( SaveTimerSeconds ) );
- SaveTimer.async_wait( bind( &DnsMaster::schedule_save, this,
- boost::asio::placeholders::error ) );
-}
-
-void DnsMaster::save_to_cachefile() const
-{ // now do the saving
- // TODO (see trusted_net_helper, boost serialization, xml)
- GlobalLogger.error() << "Actual saving not implemented yet!";
-}
-
-
-bool DnsMaster::load_from_cachefile()
-{
- // TODO: some boost serialization and xml stuff, see trusted_net_helper
- GlobalLogger.error() << "Actual loading not implemented yet!";
- return true;
-}
-
-ResolverItem DnsMaster::get_resolver_for( const std::string &hostname )
+ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname )
{
DnsMasterItem master = get_instance();
if ( master->ResolverMap.count(hostname) == 0 )
// check if it is an ip address, so can create a simple pseudo resolver
if ( master->is_ip(hostname) )
{
- ResolverItem new_resolver( new IpPseudoResolver(hostname) );
+ GlobalLogger.info() << "Creating PseudoResolver for IP "
+ << hostname;
+ ResolverItem new_resolver( new IpPseudoResolver(hostname, Cache) );
master->ResolverMap[hostname] = new_resolver;
}
else
{
- ResolverItem new_resolver( new DnsResolver(IoService,
- NameServer,
- hostname) );
+ GlobalLogger.info() << "Creating Resolver for host " << hostname;
+ ResolverItem new_resolver( new DnsResolver(hostname, Cache,
+ IoService, NameServer) );
master->ResolverMap[hostname] = new_resolver;
}
}
/**
* return true if given hostname string actually is an IP
*
- * delegates decision to boost::ip::address::from_string
+ * delegates decision to boost::asio::ip::address::from_string
*/
bool DnsMaster::is_ip(const std::string &hostname) const
{
try
{
- boost::ip::address ip = boost::ip::address::from_string(hostname);
+ boost::asio::ip::address ip = boost::asio::ip::address::from_string(
+ hostname);
return ip.is_v4() || ip.is_v6();
}
catch ( const std::exception &ex )
}
}
+void DnsMaster::unregister_resolver(const std::string &hostname)
+{
+ int n_erased_reslv = ResolverMap.erase(hostname);
+ if (n_erased_reslv == 1)
+ GlobalLogger.info() << "Unregistered resolver for " << hostname
+ << " from DNS master";
+ else
+ GlobalLogger.warning() << "Unregistered " << n_erased_reslv
+ << "(!) resolvers for " << hostname
+ << " from DNS master!";
+}
+
// (created using vim -- the world's best text editor)
Christian Herdtweck, Intra2net AG 2015
*/
+/**
+ * Two in one: a DNS resolver factory and a DNS cache
+ *
+ * Put these two things into one class because it is easier this way to avoid
+ * sync problems if e.g. there are 2 resolvers for the same host name
+ *
+ * This class is a Singleton. In case there are problems with this approach,
+ * there is an alternative:
+ * give every ResolverBase object a DnsMasterItem as variable, that is set
+ * during construction and call update / get_cached_results on that instance
+ */
+
#ifndef DNS_MASTER_H
#define DNS_MASTER_H
#include <map>
-#include <pair>
-#include <list>
-#include <boost/smart_ptr.hpp>
+#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/asio/deadline_timer.hpp>
-#include <boost/system/error_code.hpp>
-#include "dns_neww/dnsresolver.h"
+#include "host/pinger.h" // for IoserviceItem
+#include "dns_neww/dnscache.h"
+#include "dns_neww/resolverbase.h"
class DnsMaster;
-typedef boost::smart_ptr<DnsMaster> DnsMasterItem;
-typedef std::map<std::string, ResolverItem> resolver_map_type
+typedef boost::shared_ptr<DnsMaster> DnsMasterItem;
-typedef boost::posix_time::ptime timestamp_type;
-typedef std::pair<HostAddress, timestamp_type> host_with_timestamp;
-typedef std::vector<host_with_timestamp> host_ttl_time_list;
-typedef std::map<std::string, host_ttl_time_list> cache_data_type;
+typedef std::map<std::string, ResolverItem> resolver_map_type;
class DnsMaster : boost::noncopyable
{
+public:
// the two functions called during init
public:
static void create_master(const IoServiceItem &io_serv,
- const boost::ip::address &name_server,
+ const boost::asio::ip::address &name_server,
const std::string &cache_file);
- static ResolverItem get_resolver_for(const std::string &hostname);
-
-
-// friendly functions in DnsResolver and their friends here
-public:
- friend void DnsResolver::update_master(const AddressList &ips);
- friend std::string DnsResolver::get_next_ip();
- friend void cname_resolve_callback(const boost::system::error_code &error,
- const bool was_success,
- const int cname_count)
-private:
- void update_ips(const AddressList &ips);
- host_ttl_time_list get_cached_results(std::string &hostname);
-
+ ResolverItem& get_resolver_for(const std::string &hostname); // factory!
+ void unregister_resolver(const std::string &hostname);
// implementation of singleton
private:
static DnsMasterItem TheOnlyInstance;
DnsMaster(const IoServiceItem &io_serv,
- const boost::ip::address &name_server,
+ const boost::asio::ip::address &name_server,
const std::string &cache_file);
public:
+ static DnsMasterItem& get_instance();
~DnsMaster();
-
// variables
private:
IoServiceItem IoService;
- const boost::ip::address NameServer;
- std::string CacheFile;
- cache_data_type DataCache;
+ DnsCacheItem Cache;
resolver_map_type ResolverMap;
- boost::asio::deadline_timer SaveTimer;
+ const boost::asio::ip::address NameServer;
// functions
private:
- void schedule_save(const boost::system::error_code &error);
- void save_to_cachefile() const;
- void load_from_cachefile();
-
+ bool is_ip(const std::string &hostname) const;
};
#endif
namespace Config
{
- const int ResolveTimeoutSeconds = 10;
+ const int ResolveTimeoutSeconds = 5;
+ const int PauseBeforeRetrySeconds = 10;
+ const int StaleDataLongtermMinutes = 15;
const int DNS_PORT = 53;
const int UniqueID = 0xaffe;
+ const int MaxRetryCount = 5;
}
-DnsResolver::DnsResolver(IoServiceItem &io_serv,
- const boost::ip::address &name_server,
- const std::string &hostname)
- : Hostname( hostname )
+DnsResolver::DnsResolver(const std::string &hostname,
+ const DnsCacheItem cache,
+ IoServiceItem &io_serv,
+ const boost::asio::ip::address &name_server)
+ : ResolverBase( hostname, cache )
+ , IoService( io_serv )
, Socket( *io_serv, ip::udp::endpoint(ip::udp::v4(), 0) )
, ReplyBuffer()
, NameServer( name_server, DNS_PORT )
, PauseBeforeRetryTimer( *io_serv )
, StaleDataLongtermTimer( *io_serv )
, CallbackList()
- , host_ttl_time_list::const_iterator()
+ , HostAddressList::const_iterator()
, RetryCount( 0 )
, IsResolving( false )
-{
- // add name server to resolver
- resolver.addServer( nameServer );
-}
+{ }
+
+
+//==============================================================================
+// ASYNC RESOLVE
+//==============================================================================
/**
* copied here code from boost::net::dns::resolve.hpp, since want async
* operation and that is used only internally, there
* --> give credit to Andreas Haberstroh (andreas at ibusy dot com)
* from https://github.com/softwareace/Boost.DNS
+ *
+ * callbacks should be of type
+ * void resolve_callback(const boost::system::error_code &error,
+ * const bool was_success,
+ * const int cname_count)
*/
-DnsResolver::async_resolve(const callback_type callback, const int cname_count)
+DnsResolver::async_resolve(const callback_type callback)
{
// remember callback
- CallbackList.push_back(callback, cname_count);
+ CallbackList.push(callback);
// check if resolving already
if (isResolving)
{
- GlobalLogger().info() << "Call to async_resolve(" << Hostname
- << ") ignored since resolving already";
+ GlobalLogger.info()
+ << "Call to async_resolve ignored since resolving already";
return;
}
// schedule timeout
(void) ResolveTimeoutTimer.expires_from_now(seconds(ResolveTimeoutSeconds));
- ResolveTimeout.async_wait( bind( &DnsResolver::wait_timer_timeout_handler,
+ ResolveTimeout.async_wait( bind( &DnsResolver::handle_resolve_timeout,
this, boost::asio::placeholders::error) );
// send dns request
{
if ( error == boost::asio::error::operation_aborted ) // cancelled
{
- GlobalLogger.info() << "DNS resolve operation was cancelled";
+ resolve_log.info() << "DNS resolve operation was cancelled";
bool was_success = false;
- bool inc_cname = false;
- finalize_resolve(was_success, inc_cname);
+ finalize_resolve(was_success);
}
else if (error)
{
- GlobalLogger.info() << "DNS resolve resulted in error " << error
+ resolve_log.info() << "DNS resolve resulted in error " << error
<< " --> treat like unavailable";
handle_unavailable();
return;
// loop over answers, remembering ips and cnames
typedef boost::shared_ptr<resource_base_t> rr_item_type;
typedef boost::shared_ptr<cname_resource> cname_item_type;
- std::vector<HostAddress> ip_list;
+ HostAddressList ip_list;
std::vector<cname_item_type> cname_list;
BOOST_FOREACH( rr_item_type rr_item, result_message.answers() )
{
}
-void DnsResolver::handle_ips(const boost::system::error_code &error,
- const IpTtlVec &ips)
+void DnsResolver::handle_ips(const HostAddressList &ips)
{
- if (error)
- GlobalLogger.warning() << "Received error " << error
- << " in handle_ips --> exit!";
// save in cache
- update_master(ips);
+ ResolverBase::update_cache( ips );
// clean up
bool was_success = true;
- bool inc_cname = false;
- finalize_resolve(was_success, inc_cname);
+ finalize_resolve(was_success);
}
void DnsResolver::handle_unavailable()
{
// schedule new attempt in quite a while
- StaleDataLongtermTimer.expires_from_now(seconds(StaleDataLongtermSeconds));
+ StaleDataLongtermTimer.expires_from_now(minutes(StaleDataLongtermMinutes));
StaleDataLongtermTimer.async_wait(
bind( &DnsResolver::wait_timer_timeout_handler,
this, boost::asio::placeholders::error
// for now, admit failure
bool was_success = false;
- bool inc_cname = false;
- finalize_resolve(was_success, inc_cname);
+ finalize_resolve(was_success);
}
void DnsResolver::handle_cname(const std::string &canonical_name)
{
// get resolver for canonical name
- ResolverItem resolver = DnsMaster.get_instance()
+ ResolverItem resolver = DnsMaster::get_instance()
->get_resolver_for(canonical_name);
resolver->async_resolve(
bind( &DnsResolver::cname_resolve_callback,
- this, boost::asio::placeholders::error, _1, _2
+ this, boost::asio::placeholders::error,
+ canonical_name, _1, _2
)
);
void cname_resolve_callback(const boost::system::error_code &error,
+ const std::string &canonical_name,
const bool was_success,
const int cname_count)
{
- if (error)
- GlobalLogger.error() << "todo"; // TODO
- if (!was_success)
- GlobalLogger.error() << "todo"; // TODO
+ bool was_success = true;
+
+ if ( error == boost::asio::error::operation_aborted ) // cancelled
+ {
+ GlobalLogger.warning()
+ << "Recursive resolution of cname was cancelled!";
+ was_success = false;
+ }
+ else if (error)
+ {
+ GlobalLogger.warning() << "Error " << error
+ << " waiting for callback from cname resolution!"
+ was_success = false;
+ }
+ if (was_success)
+ { // tell cache to return cname's ips if queried for our hostname
+ ResolverBase::update_cache(
+ ResolverBase::get_cached_results(canonical_name) );
+ }
+ else
+ {
+ GlobalLogger.info() << "Cname resolution failed";
+ was_success = false;
+ }
+
+ finalize_resolve(was_success, cname_count+1);
+}
+
+
+void DnsResolver::finalize_resolve(const bool was_success,
+ const int cname_count)
+{
+ // stop timers
+ if (cname_count > 0)
+ stop_trying();
+ // else was called already from handle_cname
+
+ // schedule callbacks, clearing callback list
+ while ( !CallbackList.empty )
+ {
+ IoService.post( bind( CallbackList.front(),
+ boost::asio::placeholders::error,
+ was_success, cname_count ) );
+ CallbackList.pop();
+ }
+
+ // finalize
+ GlobalLogger.notice() << "Done resolving"
+ << " with success = " << was_success
+ << " and cname_count = " << cname_count;
+ IsResolving = false;
+}
+
+void DnsResolver::stop_trying()
+{
+ // cancel timers
+ GlobalLogger.debug() << "Cancelling timers";
+ ResolveTimeoutTimer.cancel();
+ PauseBeforeRetryTimer.cancel();
+ StaleDataLongtermTimer.cancel();
+
+ // clean up
+ RetryCount = 0;
+}
+
+viod DnsResolver::handle_resolve_timeout(const boost::system::error_code &error)
+{
+ if ( error == boost::asio::error::operation_aborted ) // cancelled
+ {
+ GlobalLogger.warning() << "Resolve timeout timer was cancelled!";
+ return;
+ }
+ else if (error)
+ {
+ GlobalLogger.warning() << "resolve timeout handler received error "
+ << error;
+ return;
+ }
+
+ GlobalLogger.notice() << "DNS resolving timed out";
- // get all results
- host_ttl_time_list results = DnsMaster.get_instance()->get_cached_results();
+ // increment timer
+ ++RetryCount;
+
+ if (RetryCount > MaxRetryCount)
+ {
+ handle_unavailable();
+ RetryCount = 0;
+ }
+ else
+ { // schedule retry
+ PauseBeforeRetryTimer.expires_from_now(
+ seconds(PauseBeforeRetrySeconds));
+ PauseBeforeRetryTimer.async_wait(
+ bind( &DnsResolver::wait_timer_timeout_handler,
+ this, boost::asio::placeholders::error) );
+ }
+}
+
+void DnsResolver::wait_timer_timeout_handler(
+ const boost::system::error_code &error)
+{
+ if ( error == boost::asio::error::operation_aborted ) // cancelled
+ GlobalLogger.warning() << "Resolve timeout timer was cancelled!";
+ else if (error)
+ GlobalLogger.warning() << "resolve timeout handler received error "
+ << error;
+ else
+ {
+ GlobalLogger.info() << "Done waiting --> re-try resolve";
+ async_resolve();
+ }
}
-DnsResolver::get_next_ip()
+//==============================================================================
+// RETRIEVAL
+//==============================================================================
+
+HostAddress& DnsResolver::get_next_ip()
{
// get cached data
- host_ttl_time_list cached_data = DnsMaster::get_instance()
- ->get_cached_results(Hostname);
+ ResolverBase::get_cached_results();
+
+ // if no results cached, return default-constructed HostAddress (0.0.0.0)
+ if ( cached_data.empty() )
+ return HostAddress;
+ // check validity of index (cache may have changed since last call)
+ if (NextIpIndex >= cached_data.size())
+ NextIpIndex = 0;
+ // return next IP
+ return cached_data[NextIpIndex++];
}
// (created using vim -- the world's best text editor)
#include "dns_neww/dnsmaster.h"
-#include <list>
+#include <queue>
#include <boost/asio/deadline_timer.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/address.hpp>
#include <boost/system/error_code.hpp>
+#include <boost/net/network_array.hpp>
+#include "host/pinger.h" // for IoServiceItem
#include "dns_neww/resolverbase.h"
#include "dns_neww/dnsmaster.h"
+#include "dns_neww/dnscache.h"
-typedef callback_type
typedef std::list<callback_type> callback_list_type;
-typedef std::vector<HostAddress> IpTtlVec;
+typedef std::queue<HostAddress> IpTtlVec;
class DnsResolver : public ResolverBase
{
-// constructor accessible from friend DnsMaster
public:
- friend DnsMaster::get_resolver_for(const std::string &hostname);
+ ~DnsResolver();
+// constructor accessible from friend DnsMaster
+public:
+ friend DnsResolverItem DnsMaster::get_resolver_for(const std::string&);
private:
- DnsResolver(IoServiceItem &io_serv,
- const boost::ip::address &name_server,
- const std::string &hostname);
+ DnsResolver(const std::string &hostname,
+ const DnsCacheItem cache,
+ IoServiceItem &io_serv,
+ const boost::asio::ip::address &name_server);
-// only real public function (called from pingers)
+// only real public functions (called from pingers)
public:
- std::string get_next_ip();
+ void async_resolve(const callback_type &callback);
+ HostAddress& get_next_ip();
private:
- void async_resolve(const callback_type &callback, const int cname_count=0);
void handle_resolve_timeout(const boost::system::error_code &error);
void handle_dns_result(const boost::system::error_code &error,
const std::size_t bytes_transferred);
void cname_resolve_callback(const boost::system::error_code &error,
const bool was_success,
const int cname_count);
- void update_master(const AddressList &ips);
- void finalize_resolve(const bool success, const bool inc_cname);
+ void finalize_resolve(const bool success, const int cname_count=0);
+ void stop_trying();
+ void wait_timer_timeout_handler(const boost::system::error_code &error);
private:
- const std::string Hostname;
- ip::udp::socket Socket;
- dns_buffer_t ReplyBuffer;
- ip::udp::endpoint NameServer;
+ IoServiceItem IoService;
+ boost::asio::ip::udp::socket Socket;
+ boost::net::dns_buffer_t ReplyBuffer;
+ boost::asio::ip::udp::endpoint NameServer;
boost::asio::deadline_timer ResolveTimeoutTimer;
boost::asio::deadline_timer PauseBeforeRetryTimer;
boost::asio::deadline_timer StaleDataLongtermTimer;
callback_list_type CallbackList;
- host_ttl_time_list::const_iterator NextIpIter;
+ int NextIpIndex;
int RetryCount;
bool IsResolving;
+};
-}
#endif
// (created using vim -- the world's best text editor)
#include "dns_neww/resolverbase.h"
#include "dns_neww/dnsmaster.h"
+namespace Config
+{
+ uint32_t DefaultTtl = 60*60*24*356; // 1 year in seconds (approx)
+}
+
/** @brief Degenerate case of a resolver: hostname is already an IP
*
* created by DnsMaster if given an IP address as hostname
{
// constructor accessible from friend DnsMaster
public:
- friend DnsMaster::create_resolver_for(const std::string &hostname);
+ friend ResolverItem& DnsMaster::get_resolver_for(
+ const std::string &hostname);
private:
- IpPseudoResolver(const std::string ip) : IP(ip) {}
+ IpPseudoResolver(const std::string &ip,
+ const DnsCacheItem &cache )
+ : ResolverBase( ip, cache )
+ , Ip( ip, Config::DefaultTtl )
+ {}
private:
- const std::string IP;
+ HostAddress Ip;
-// only function, inherited from ResolverBase
+// only functions, inherited from ResolverBase
public:
- std::string get_next_ip() { return IP; }
+ HostAddress& get_next_ip() { return Ip; }
+ void async_resolve(const callback_type &callback)
+ {
+ IoService.post( bind(callback, true, 0) );
+ }
};
#endif
#include <boost/shared_ptr.hpp>
+#include "dns/hostaddress.h"
+#include "dns_neww/dnscache.h"
+#include "dns_neww/dnsmaster.h"
+
+
+class ResolverBase;
+typedef boost::shared_ptr<ResolverBase> ResolverItem;
+
+typedef void (*callback_type)(const bool, const int);
+
/**
* @brief: abstract base class for DnsResolver and IpPseudoResolver
*/
class ResolverBase
{
public:
- virtual std::string get_next_ip() = 0;
-};
+ virtual HostAddress& get_next_ip() = 0;
+ virtual void async_resolve(const callback_type &callback) = 0;
+ virtual ~ResolverBase()
+ {
+ DnsMaster::get_instance()->unregister(Hostname);
+ }
-typedef boost::shared_ptr<ResolverBase> ResolverItem;
+protected:
+ ResolverBase(const std::string &hostname,
+ const DnsCacheItem &cache )
+ : Hostname( hostname )
+ , Cache( cache )
+ {}
+
+// variables
+private:
+ std::string Hostname;
+ DnsCacheItem Cache;
+
+// functions for subclasses
+protected:
+ void update_cache( const HostAddressList &new_results ) const
+ { Cache->update( Hostname, new_results ); }
+
+ HostAddressList get_cached_results(const std::string host="") const
+ {
+ if (host.empty())
+ return Cache->get_data( Hostname );
+ else
+ return Cache->get_data( host );
+ }
+};
#endif
class IcmpPacketDistributor;
typedef boost::shared_ptr<IcmpPacketDistributor> IcmpPacketDistributorItem;
-typedef boost::shared_ptr<boost::asio::io_service> IoServiceItem;
typedef boost::shared_ptr<icmp::socket> SocketItem;
//-----------------------------------------------------------------------------