#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
+#include "dns/dnsmaster.h"
+
using boost::bind;
using boost::posix_time::seconds;
using I2n::Logger::GlobalLogger;
namespace Config
{
int SaveTimerSeconds = 60;
+ int MaxRetrievalRecursions = 10;
}
-
-
DnsCache::DnsCache(const IoServiceItem &io_serv,
const std::string &cache_file)
: IpCache()
void DnsCache::update(const std::string &hostname,
- const std::string &cname)
+ const Cname &cname)
{
GlobalLogger.info() << "DnsCache: update CNAME for " << hostname
- << " to " << cname;
+ << " to " << cname.first;
CnameCache[hostname] = cname;
HasChanged = true;
}
-void DnsCache::update_ttl(const std::string &hostname,
+void DnsCache::update(const std::string &hostname,
const uint32_t new_ttl)
{
GlobalLogger.info() << "DnsCache: ensure TTL for IPs for " << hostname
}
-HostAddressVec& DnsCache::get_ips(const std::string &hostname)
+HostAddressVec DnsCache::get_ips(const std::string &hostname,
+ const bool check_up_to_date)
{
+ HostAddressVec result = IpCache[hostname];
+ if (check_up_to_date)
+ {
+ HostAddressVec result_up_to_date;
+ int threshold = DnsMaster::get_instance()
+ ->get_resolved_ip_ttl_threshold();
+ BOOST_FOREACH( const HostAddress &addr, result )
+ {
+ if (addr.get_ttl().get_updated_value() > threshold)
+ result_up_to_date.push_back(addr);
+ }
+ GlobalLogger.debug() << "DnsCache: From cached list of size "
+ << result.size() << " return " << result_up_to_date.size()
+ << " since rest out of date";
+ result = result_up_to_date;
+ }
GlobalLogger.info() << "DnsCache: request IPs for " << hostname
- << " --> " << IpCache[hostname].size() << "-list";
- return IpCache[hostname];
+ << " --> " << result.size() << "-list";
+ return result;
}
-std::string& DnsCache::get_cname(const std::string &hostname)
+std::string DnsCache::get_cname(const std::string &hostname,
+ const bool check_up_to_date)
{
+ Cname result_obj = CnameCache[hostname];
GlobalLogger.info() << "DnsCache: request CNAME for " << hostname
- << " --> \"" << CnameCache[hostname] << "\"";
- return CnameCache[hostname];
+ << " --> \"" << result_obj.first << "\"";
+ if (check_up_to_date)
+ {
+ if (result_obj.second.get_updated_value() > DnsMaster::get_instance()
+ ->get_resolved_ip_ttl_threshold())
+ return result_obj.first;
+ else
+ {
+ GlobalLogger.debug() << "DnsCache: Cname is out of date";
+ return "";
+ }
+ }
+ else
+ return result_obj.first;
}
-HostAddressVec& DnsCache::get_ips_recursive(const std::string &hostname)
+// underlying assumption in this function: for a hostname, the cache has either
+// a list of IPs saved or a cname saved, but never both
+HostAddressVec DnsCache::get_ips_recursive(const std::string &hostname,
+ const bool check_up_to_date)
{
std::string current_host = hostname;
- HostAddressVec& result = get_ips(current_host);
+ HostAddressVec result = get_ips(current_host);
+ int n_recursions = 0;
while ( result.empty() )
{
- current_host = get_cname(current_host);
+ current_host = get_cname(current_host, check_up_to_date);
if (current_host.empty())
break;
+ else if (++n_recursions >= Config::MaxRetrievalRecursions)
+ {
+ GlobalLogger.warning() << "DnsCache: reached recursion limit of "
+ << n_recursions << " in recursive IP retrieval!";
+ break;
+ }
else
- result = get_ips(current_host);
+ result = get_ips(current_host, check_up_to_date);
}
return result;
}
#include "host/pinger.h" // for IoserviceItem
#include "dns/hostaddress.h"
+#include "dns/timetolive.h"
typedef std::vector<HostAddress> HostAddressVec;
typedef std::map<std::string, HostAddressVec> ip_map_type;
-typedef std::map<std::string, std::string> cname_map_type;
+typedef std::pair<std::string, TimeToLive> Cname;
+typedef std::map<std::string, Cname> cname_map_type;
+
class DnsCache
{
// accessed from ResolverBase subclasses
void update(const std::string &hostname, const HostAddressVec &new_data);
- void update(const std::string &hostname, const std::string &cname);
- void update_ttl(const std::string &hostname, const uint32_t ttl);
- HostAddressVec& get_ips(const std::string &hostname);
- std::string& get_cname(const std::string &hostname);
- HostAddressVec& get_ips_recursive(const std::string &hostname);
+ void update(const std::string &hostname, const Cname &cname);
+ void update(const std::string &hostname, const uint32_t ttl);
+ HostAddressVec get_ips(const std::string &hostname,
+ const bool check_up_to_date=false);
+ std::string get_cname(const std::string &hostname,
+ const bool check_up_to_date=false);
+ HostAddressVec get_ips_recursive(const std::string &hostname,
+ const bool check_up_to_date=false);
// variables
private:
const PingProtocol &ping_protocol )
{
// find suitable DnsIpProtocol for ping protocol
- DnsIpProtocol protocol = DnsMaster::ping2dns_protocol(ping_protocol);
+ DnsIpProtocol protocol = ping2dns_protocol(ping_protocol);
return get_resolver_for(hostname, protocol);
}
ResolverItem& DnsMaster::get_resolver_for(const std::string &hostname,
const DnsIpProtocol &protocol)
{
- DnsMasterItem master = get_instance();
-
// create key to ResolverMap
resolver_key_type key(hostname, protocol);
- if ( master->ResolverMap.count(key) == 0 )
+ if ( ResolverMap.count(key) == 0 )
{ // need to create a resolver
// check if it is an ip address, so can create a simple pseudo resolver
- if ( master->is_ip(hostname) )
+ if ( is_ip(hostname) )
{
boost::asio::ip::address ip
= boost::asio::ip::address::from_string(hostname);
ResolverItem new_resolver( new IpPseudoResolver(IoService,
hostname,
Cache) );
- master->ResolverMap[key] = new_resolver;
+ ResolverMap[key] = new_resolver;
}
else
{
- GlobalLogger.info() << "Creating Resolver for host " << hostname;
+ GlobalLogger.info() << "DnsMaster: Creating Resolver for host "
+ << hostname << " and protocol " << to_string(protocol);
ResolverItem new_resolver( new DnsResolver(IoService,
hostname,
protocol,
Cache,
DefaultNameServer) );
- master->ResolverMap[key] = new_resolver;
+ ResolverMap[key] = new_resolver;
}
}
- return master->ResolverMap[key];
+ return ResolverMap[key];
}
// create resolver but do not remember it in ResolverMap
const DnsIpProtocol &protocol,
const boost::asio::ip::address &name_server)
{
+ resolver_key_type key(hostname, protocol);
+ if ( !ResolverMap[key] )
+ GlobalLogger.warning() << "DnsMaster: requesting recursor for host "
+ << hostname << " and protocol " << to_string(protocol)
+ << " but have no regular resolver for this combination!";
+ else
+ GlobalLogger.warning() << "DnsMaster: requesting recursor for host "
+ << hostname << " and protocol " << to_string(protocol);
+
ResolverItem new_resolver( new DnsResolver(IoService,
hostname,
protocol,
std::string to_string(const DnsIpProtocol &protocol);
+/**
+ * Factory and Cache of DNS resolvers
+ *
+ * to avoid having several resolvers resolving the same hostname which might
+ * result in conflicts with caching, this class is a singleton factory and the
+ * only place where Resolvers are constructed. They are remembered in an
+ * internal cache by hostname and IP version requested (v4, v6 or both).
+ *
+ * During resolving, several different name servers will have to be queried for
+ * the same hostname. These recursive resolvers are created using
+ * get_recursor_for and are NOT cached, so they should only be used from another
+ * "regular" resolver (created using get_resolver_for)
+ *
+ * The DnsMaster also remembers a few global variables that can be queried
+ * using public getter functions and it creates the DnsCache used by all its
+ * resolvers
+ */
class DnsMaster : boost::noncopyable
{
// Resolver factory
// storage of global variables
public:
- //boost::asio::ip::address &get_name_server() const; // currently unused
+ //boost::asio::ip::address &get_default_name_server() const; // unused
int get_resolved_ip_ttl_threshold() const;
int get_max_address_resolution_attempts() const;
namespace Config
{
- const int ResolveTimeoutSeconds = 0;
+ const int ResolveTimeoutSeconds = 3;
const int PauseBeforeRetrySeconds = 10;
const int StaleDataLongtermMinutes = 15;
const int DNS_PORT = 53;
// owner of data and that exists until end of function
// Items in answers list are shared_ptr to resource_base_t
std::vector<host_addr_pair> result_ips;
- std::vector<string_pair> result_cnames;
- std::vector<string_pair> result_nameservers;
+ std::vector<src_cname_pair> result_cnames;
+ std::vector<string_pair> result_name_servers;
+ GlobalLogger.debug() << "Checking ANSWERS section of dns reply";
gather_results(result_message.answers(), &result_ips, &result_cnames,
- &result_nameservers);
+ &result_name_servers);
// results should have the logical order
// Hostname [ --> cname1 --> cname2 --> ... --> cnameN ] [ --> ips ]
// remember cname list (if there were any)
- BOOST_FOREACH( const string_pair &host_and_cname, result_cnames )
+ BOOST_FOREACH( const src_cname_pair &host_and_cname, result_cnames )
+ {
+ GlobalLogger.debug() << LogPrefix << "Remember CNAME "
+ << host_and_cname.first << " --> " << host_and_cname.second.first;
ResolverBase::update_cache(host_and_cname.first, host_and_cname.second);
+ }
if ( !result_ips.empty() )
handle_ips( result_ips );
// re-start resolving with that
handle_cname(result_cnames);
else
- { // no answers --> check for nameservers in authorities section
- if ( !result_nameservers.empty() )
+ { // no answers --> check for name_servers in authorities section
+ if ( !result_name_servers.empty() )
GlobalLogger.warning() << LogPrefix
<< "Received NS records in answers! "
<< "That is quite unexpected...";
+ GlobalLogger.debug() << "Checking AUTHORITIES section of dns reply";
gather_results(result_message.authorites(), &result_ips,
- &result_cnames, &result_nameservers);
+ &result_cnames, &result_name_servers);
+ GlobalLogger.debug() << "Checking ADDITIONALS section of dns reply";
gather_results(result_message.additionals(), &result_ips,
- &result_cnames, &result_nameservers);
+ &result_cnames, &result_name_servers);
- // search for a nameserver for which an IP is given
+ // search for a name_server for which an IP is given
bool have_recursed = false;
- BOOST_FOREACH( const string_pair &nameserver, result_nameservers )
+ BOOST_FOREACH( const string_pair &name_server, result_name_servers )
{
+ if (name_server.second == Hostname)
+ { // in case we try to resolve IP for name server, do not use same
+ GlobalLogger.debug() << LogPrefix
+ << "Name server found is same as hostname --> skip";
+ continue;
+ }
+
// go through ips and look for match
BOOST_FOREACH( const host_addr_pair &host_and_addr, result_ips )
{
- if (nameserver.second == host_and_addr.first)
+ if (name_server.second == host_and_addr.first)
{
- GlobalLogger.info() << LogPrefix << "Ask next nameserver "
- << nameserver.second << " with IP "
+ GlobalLogger.info() << LogPrefix << "Ask next name_server "
+ << name_server.second << " with IP "
<< host_and_addr.second.get_ip() << " (responsible for "
- << nameserver.first << ")";
+ << name_server.first << ")";
have_recursed = true;
handle_recurse( host_and_addr.second );
break;
}
if ( !have_recursed )
- { // no nameserver with ip found -- strange
- if (result_nameservers.empty())
+ { // no name_server with ip found -- strange
+ if (result_name_servers.empty())
{
GlobalLogger.error() << LogPrefix << "Result contained neither "
<< "IP nor CNAME nor name server --> cannot proceed!";
}
else
{
- // TODO: check in cache for nameserver ips?
-
GlobalLogger.warning() << LogPrefix
- << "There are " << result_nameservers.size()
- << " nameservers given but none with IP "
- << "--> need to resolve nameserver -- this sucks!";
- //handle_recurse_without_ip(result_nameservers[0].second);
-
- // would have to create a new resolver with previous nameserver
- // to resolve new nameserver name; save in Recursor
- // In callback reset Recursor, get ip(s) and continue in
- // handle_recurse
- GlobalLogger.warning() << LogPrefix << "Have not implemented "
- << "resolution of name server; I sincerely hope this never "
- << "happens or can be dealt with more easily another way!";
- handle_unavailable();
+ << "There are " << result_name_servers.size()
+ << " name_servers given but none with IP!";
+ handle_recurse_without_ip(result_name_servers[0].second);
}
}
}
void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers,
std::vector<host_addr_pair> *result_ips,
- std::vector<string_pair> *result_cnames,
- std::vector<string_pair> *result_nameservers)
+ std::vector<src_cname_pair> *result_cnames,
+ std::vector<string_pair> *result_name_servers)
const
{
using boost::net::dns::resource_base_t;
+ boost::posix_time::ptime now =boost::posix_time::second_clock::local_time();
BOOST_FOREACH( boost::shared_ptr<resource_base_t> rr_item, *answers )
{
boost::net::dns::type_t rr_type = rr_item->rtype();
uint32_t ttl = rr_item->ttl();
std::string domain = rr_item->domain();
+ std::string expiry =
+ boost::posix_time::to_simple_string(now + seconds(ttl));
if (rr_type == boost::net::dns::type_a)
{ // 'A' resource records carry IPv4 addresses
( dynamic_cast<boost::net::dns::a_resource *> (rr_item.get()) )
->address();
result_ips->push_back(host_addr_pair(domain, HostAddress(ip, ttl)));
- GlobalLogger.debug() << LogPrefix << "IPv4 " << ip << " with TTL "
- << ttl << "s for " << domain;
+ GlobalLogger.debug() << LogPrefix << domain << ": IPv4 " << ip
+ << " with TTL " << ttl << "s (until "
+ << expiry << ")";
}
else if (rr_type == boost::net::dns::type_a6)
{ // 'AAAA' resource records carry IPv6 addresses
( dynamic_cast<boost::net::dns::a6_resource *> (rr_item.get()) )
->address();
result_ips->push_back(host_addr_pair(domain, HostAddress(ip, ttl)));
- GlobalLogger.debug() << LogPrefix << "IPv6 " << ip << " with TTL "
- << ttl << "s for " << domain;
+ GlobalLogger.debug() << LogPrefix << domain << ": IPv6 " << ip
+ << " with TTL " << ttl << "s (until "
+ << expiry << ")";
}
else if (rr_type == boost::net::dns::type_cname)
{ // 'CNAME' resource records that carry aliases
std::string cname =
(dynamic_cast<boost::net::dns::cname_resource *>(rr_item.get()))
->canonicalname();
- result_cnames->push_back( string_pair(domain, cname) );
- GlobalLogger.debug() << LogPrefix << "CNAME " << cname
- << " with TTL " << ttl << "s for " << domain;
+ result_cnames->push_back( src_cname_pair(domain,
+ Cname(cname, ttl)) );
+ GlobalLogger.debug() << LogPrefix << domain << ": CNAME to "
+ << cname << " with TTL " << ttl << "s (until "
+ << expiry << ")";
}
else if (rr_type == boost::net::dns::type_ns)
- { // NS (nameserver) resource records
- std::string nameserver =
+ { // NS (name_server) resource records
+ std::string name_server =
(dynamic_cast<boost::net::dns::ns_resource *>(rr_item.get()))
->nameserver();
- result_nameservers->push_back( string_pair(domain, nameserver) );
- GlobalLogger.debug() << LogPrefix << "NameServer " << nameserver
- << " with TTL " << ttl << "s for " << domain;
+ result_name_servers->push_back( string_pair(domain, name_server) );
+ GlobalLogger.debug() << LogPrefix << "NameServer " << name_server
+ << " for " << domain << " with TTL " << ttl
+ << "s (until " << expiry << ")";
}
else if (rr_type == boost::net::dns::type_soa)
GlobalLogger.debug() << LogPrefix << "SOA resource";
}
-void DnsResolver::handle_cname(const std::vector<string_pair> &result_cnames)
+void DnsResolver::handle_cname(const std::vector<src_cname_pair> &result_cnames)
{
// find the "last" cname in the list
// Hostname --> cname1 --> cname2 --> ... --> cnameN
// We assume here that this list might not be in order but that all cnames
- // form a single list (without a break)
+ // form a single list (form one connected list and not several isolated)
+
+ // host_and_cname.second is a Cname, which is a pair (destination, ttl)
std::string last_cname = "";
bool could_be_last;
- BOOST_REVERSE_FOREACH( const string_pair &host_and_cname, result_cnames )
+ BOOST_REVERSE_FOREACH( const src_cname_pair &host_and_cname, result_cnames )
{
could_be_last = true;
- BOOST_REVERSE_FOREACH( const string_pair &other, result_cnames )
+ BOOST_REVERSE_FOREACH( const src_cname_pair &other, result_cnames )
{
- if (other.first == host_and_cname.second)
+ if (other.first == host_and_cname.second.first)
{ // found cname for current cname
could_be_last = false;
break;
}
if (could_be_last)
{
- last_cname = host_and_cname.second;
+ last_cname = host_and_cname.second.first;
break;
}
}
<< "Could not identify \"last\" CNAME to handle -- "
<< "maybe we encountered a CNAME loop? Anyway, cannot proceed!";
GlobalLogger.info() << LogPrefix << "Result CNAMEs were:";
- BOOST_FOREACH( const string_pair &host_and_cname, result_cnames )
+ BOOST_FOREACH( const src_cname_pair &host_and_cname, result_cnames )
GlobalLogger.info() << LogPrefix << host_and_cname.first << " --> "
- << host_and_cname.second;
+ << host_and_cname.second.first;
handle_unavailable();
}
else
else
Recursor.reset();
- f ( OperationCancelled )
+ if ( OperationCancelled )
{ // async_resolve was cancelled --> callbacks already called
GlobalLogger.info() << LogPrefix
<< "Ignoring recursion results since we were cancelled";
else if (was_success)
{
// make sure the saved TTL is not larger than the one we found here
- ResolverBase::update_cache_ttl(min_ttl);
+ ResolverBase::update_cache(min_ttl);
finalize_resolve(was_success, recursion_count+1);
}
else
}
+void DnsResolver::handle_recurse_without_ip(const std::string &name_server)
+{
+ // get resolver for name_server
+ // save in Recursor although it is a "proper" resolver (so result is cached)
+ if (Recursor)
+ {
+ if (Recursor->is_resolving())
+ {
+ GlobalLogger.warning() << LogPrefix << "Recursor is resolving! "
+ << "Will cancel and reset";
+ Recursor->cancel_resolve();
+ }
+ else
+ GlobalLogger.warning() << LogPrefix
+ << "Recursor has not been reset!";
+ Recursor.reset();
+ }
+ Recursor = DnsMaster::get_instance()->get_resolver_for(name_server,
+ Protocol);
+
+ // check for IPs in cache
+ if (Recursor->get_resolved_ip_count() == 0)
+ {
+ GlobalLogger.info() << LogPrefix
+ << "Start to resolve address of name server " << name_server;
+ callback_type callback = boost::bind(
+ &DnsResolver::name_server_resolve_callback,
+ this, _1, _2);
+ Recursor->async_resolve( callback );
+ }
+ else
+ {
+ GlobalLogger.info() << LogPrefix << "Use cached ip for name server "
+ << name_server;
+ HostAddress ip = Recursor->get_next_ip();
+ Recursor.reset();
+ handle_recurse(ip);
+ }
+}
+
+void DnsResolver::name_server_resolve_callback(const bool was_success,
+ const int recursion_count)
+{
+ if (OperationCancelled)
+ {
+ GlobalLogger.info() << LogPrefix
+ << "Ignoring name server IP results since we were cancelled";
+ return;
+ }
+ else if (was_success)
+ {
+ HostAddress ip = Recursor->get_next_ip();
+ GlobalLogger.info() << LogPrefix << "Found IP " << ip.get_ip()
+ << " for name server " << Recursor->get_hostname();
+ Recursor.reset();
+ handle_recurse(ip);
+ }
+ else
+ {
+ GlobalLogger.info() << LogPrefix << "Failed to find IP for name server"
+ << Recursor->get_hostname() << " --> schedule retry";
+ Recursor.reset();
+ schedule_retry();
+ }
+}
+
+
void DnsResolver::finalize_resolve(const bool was_success,
const int recursion_count)
{
}
+/**
+ * cancel a earlier call to async_resolve
+ *
+ * callbacks will be called with was_success=false; all internal operations
+ * will be cancelled and internal callbacks (timers, dns results) have no
+ * effect any more
+ */
void DnsResolver::cancel_resolve()
{
if ( !IsResolving )
Recursor->cancel_resolve(); // does not hurt even if it is not resolving
// set before finalize_resolve so can check in finalize_resolve that ID is
- // always 0; ID is not used any more since handle_dns_result stops if
+ // always 0; ID is not used any more since handle_dns_result stops if
// OperationCancelled is true
RequestId = 0;
finalize_resolve(was_success, recursion_count);
// set after finalize_resolve, so can check in finalize_resolve that
- // cancel is never true
+ // OperationCancelled is never true
OperationCancelled = true;
}
{
GlobalLogger.warning() << LogPrefix
<< "resolve timeout handler received error "
- << error;
- return;
+ << error << " --> retry";
+ schedule_retry();
}
else if ( OperationCancelled )
{ // async_resolve was cancelled --> callbacks already called
GlobalLogger.info() << LogPrefix
- << "Ignoring DNS timeout since we were cancelled";
+ << "Ignoring DNS timeout since we were cancelled";
return;
}
else
{
GlobalLogger.notice() << LogPrefix << "DNS resolving timed out";
-
schedule_retry();
}
}
void DnsResolver::schedule_retry()
{
- // clean up a bit
+ // this function is called in all sorts of error cases
+ // --> need to clean up a bit
if ( Recursor )
{
- Recursor.cancel();
+ Recursor->cancel_resolve();
Recursor.reset();
}
ResolveTimeoutTimer.cancel();
bool DnsResolver::have_up_to_date_ip()
{
- // get cached data
- HostAddressVec cached_data = ResolverBase::get_cached_ips_recursively();
-
- // get threshold
- uint32_t resolved_ip_ttl_threshold = static_cast<uint32_t>(
- DnsMaster::get_instance()->get_resolved_ip_ttl_threshold() );
-
- // loop over addresses
- BOOST_FOREACH( const HostAddress &addr, cached_data )
- {
- uint32_t ttl = addr.get_ttl().get_updated_value();
- if ( ttl > resolved_ip_ttl_threshold )
- return true;
- }
-
- // if not returned true by now, we have tried all IPs without success
- return false;
+ return ! ResolverBase::get_cached_ips_recursively("", true).empty();
}
int DnsResolver::get_resolved_ip_count()
typedef std::pair<std::string, std::string> string_pair;
+typedef std::pair<std::string, Cname> src_cname_pair;
typedef std::pair<std::string, HostAddress> host_addr_pair;
const std::size_t bytes_transferred);
void handle_unavailable();
void handle_ips(const std::vector<host_addr_pair> &result_ips);
- void handle_cname(const std::vector<string_pair> &result_cnames);
+ void handle_cname(const std::vector<src_cname_pair> &result_cnames);
void handle_recurse(const HostAddress &name_server);
+ void handle_recurse_without_ip(const std::string &name_server);
void cname_resolve_callback(const bool was_success,
const int recursion_count);
void recursive_resolve_callback(const uint32_t min_ttl,
const bool was_success,
const int recursion_count);
+ void name_server_resolve_callback(const bool was_success,
+ const int recursion_count);
+ void schedule_retry();
void finalize_resolve(const bool success, const int recursion_count=0);
void stop_trying();
void wait_timer_timeout_handler(const boost::system::error_code &error);
void gather_results( const boost::net::dns::rr_list_t *answers,
std::vector<host_addr_pair> *result_ips,
- std::vector<string_pair> *result_cnames,
+ std::vector<src_cname_pair> *result_cnames,
std::vector<string_pair> *result_nameservers ) const;
// variables
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
#include "dns/timetolive.h"
void save(Archive & ar, const unsigned int version) const
{
std::string ip = Ip.to_string();
- std::string ttl_creation_time = boost::posix_time::to_iso_string(
- Ttl.TtlSetTime);
ar & BOOST_SERIALIZATION_NVP(ip);
- ar & BOOST_SERIALIZATION_NVP(Ttl.Ttl);
- ar & BOOST_SERIALIZATION_NVP(ttl_creation_time);
+ ar & BOOST_SERIALIZATION_NVP(Ttl);
}
template<class Archive>
void load(Archive & ar, const unsigned int version)
{
std::string ip;
- uint32_t ttl_seconds;
- std::string ttl_creation_time;
ar & BOOST_SERIALIZATION_NVP(ip);
- ar & BOOST_SERIALIZATION_NVP(ttl_seconds);
- ar & BOOST_SERIALIZATION_NVP(ttl_creation_time);
-
- // now convert to Ip and Ttl
+ ar & BOOST_SERIALIZATION_NVP(Ttl);
Ip = boost::asio::ip::address::from_string(ip);
- Ttl = TimeToLive();
- Ttl.Ttl = ttl_seconds;
- Ttl.TtlSetTime = boost::posix_time::from_iso_string(ttl_creation_time);
+
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
, CallbackList()
{}
+std::string ResolverBase::get_hostname() const
+{ return Hostname; }
+
void ResolverBase::update_cache( const std::string &hostname,
const HostAddressVec &new_results ) const
{ Cache->update( hostname, new_results ); }
void ResolverBase::update_cache( const std::string &hostname,
- const std::string &cname ) const
+ const Cname &cname ) const
{ Cache->update( hostname, cname ); }
void ResolverBase::update_cache( const HostAddressVec &new_results ) const
{ Cache->update( Hostname, new_results ); }
-void ResolverBase::update_cache( const std::string &cname ) const
+void ResolverBase::update_cache( const Cname &cname ) const
{ Cache->update( Hostname, cname ); }
-void ResolverBase::update_cache_ttl( const uint32_t ttl ) const
-{ Cache->update_ttl( Hostname, ttl ); }
+void ResolverBase::update_cache( const uint32_t ttl ) const
+{ Cache->update( Hostname, ttl ); }
-HostAddressVec& ResolverBase::get_cached_ips_recursively(const std::string host)
- const
+HostAddressVec ResolverBase::get_cached_ips_recursively(const std::string host,
+ bool check_up_to_date) const
{
if (host.empty())
- return Cache->get_ips_recursive(Hostname);
+ return Cache->get_ips_recursive(Hostname, check_up_to_date);
else
- return Cache->get_ips_recursive(host);
+ return Cache->get_ips_recursive(host, check_up_to_date);
}
void ResolverBase::schedule_callbacks(const bool was_success,
virtual bool have_up_to_date_ip() = 0;
virtual int get_resolved_ip_count() = 0;
+ std::string get_hostname() const;
+
protected:
ResolverBase(const IoServiceItem &io_serv,
const std::string &hostname,
// variables
protected:
IoServiceItem IoService;
- std::string Hostname;
+ const std::string Hostname;
DnsCacheItem Cache;
callback_list_type CallbackList;
protected:
virtual void do_resolve() = 0;
+ // convenient forwards to DnsCache that just insert Hostname
void update_cache( const HostAddressVec &new_results ) const;
- void update_cache( const std::string &cname ) const;
+ void update_cache( const Cname &cname ) const;
void update_cache( const std::string &hostname,
const HostAddressVec &new_results ) const;
void update_cache( const std::string &hostname,
- const std::string &cname ) const;
- void update_cache_ttl( const uint32_t ttl ) const;
+ const Cname &cname ) const;
+ void update_cache( const uint32_t ttl ) const;
- HostAddressVec& get_cached_ips_recursively(const std::string host="") const;
+ HostAddressVec get_cached_ips_recursively(const std::string host="",
+ const bool check_up_to_date=false) const;
void schedule_callbacks(const bool was_success,
const int cname_count);
#include <stdint.h>
#include <boost/asio.hpp>
-//#include "dns/hostaddress.h"
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/serialization/split_member.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
// forward declaration
class HostAddress;
/// the time when the time-to-live was set, so it is possible to know the
/// elapsed time
boost::posix_time::ptime TtlSetTime;
+
+ // serialization
+ friend class boost::serialization::access;
+ template<class Archive>
+ void save(Archive & ar, const unsigned int version) const
+ {
+ std::string ttl_creation_time = boost::posix_time::to_iso_string(
+ TtlSetTime);
+ ar & BOOST_SERIALIZATION_NVP(Ttl);
+ ar & BOOST_SERIALIZATION_NVP(ttl_creation_time);
+ }
+
+ template<class Archive>
+ void load(Archive & ar, const unsigned int version)
+ {
+ uint32_t ttl_seconds;
+ std::string ttl_creation_time;
+ ar & BOOST_SERIALIZATION_NVP(ttl_seconds);
+ ar & BOOST_SERIALIZATION_NVP(ttl_creation_time);
+
+ // now convert to Ip and Ttl
+ Ttl = ttl_seconds;
+ TtlSetTime = boost::posix_time::from_iso_string(ttl_creation_time);
+ }
+
+ BOOST_SERIALIZATION_SPLIT_MEMBER()
};
#endif // TIME_TO_LIVE_H