, Ttl( ttl )
{}
+Cname::Cname(const std::string &host, const TimeToLive &ttl)
+ : Host( host )
+ , Ttl( ttl )
+{}
+
DnsCache::DnsCache(const IoServiceItem &io_serv,
const std::string &cache_file)
: IpCache()
DnsCache::~DnsCache()
{
- GlobalLogger.info() << "Dns Cache is being destructed";
+ GlobalLogger.info() << "DnsCache: being destructed";
// save one last time without re-scheduling the next save
save_to_cachefile();
void DnsCache::save_to_cachefile()
{
if (!HasChanged)
- {
GlobalLogger.info() << "DnsCache: skip saving because has not changed";
- return;
- }
else if (CacheFile.empty())
- {
GlobalLogger.warning()
<< "DnsCache: skip saving because file name empty!";
- return;
- }
-
- try
- {
- std::ofstream ofs( CacheFile.c_str() );
- boost::archive::xml_oarchive oa(ofs);
- oa << boost::serialization::make_nvp("IpCache", IpCache);
- oa << boost::serialization::make_nvp("CnameCache", CnameCache);
- GlobalLogger.info() << "DnsCache: saved to cache file " << CacheFile;
-
- HasChanged = false;
- }
- catch (std::exception &exc)
+ else if (CacheFile == DO_NOT_USE_CACHE_FILE)
+ GlobalLogger.info() << "DnsCache: configured not to use cache file";
+ else
{
- GlobalLogger.warning() << "Saving failed: " << exc.what();
+ try
+ {
+ std::ofstream ofs( CacheFile.c_str() );
+ boost::archive::xml_oarchive oa(ofs);
+ //oa << boost::serialization::make_nvp("IpCache", IpCache);
+ //oa << boost::serialization::make_nvp("CnameCache", CnameCache);
+ oa & BOOST_SERIALIZATION_NVP(IpCache);
+ oa & BOOST_SERIALIZATION_NVP(CnameCache);
+ GlobalLogger.info() << "DnsCache: saved to cache file " << CacheFile;
+
+ HasChanged = false;
+ }
+ catch (std::exception &exc)
+ {
+ GlobalLogger.warning() << "Saving failed: " << exc.what();
+ }
}
}
-
void DnsCache::load_from_cachefile()
{
if (CacheFile.empty())
- {
GlobalLogger.warning()
<< "DnsCache: cannot load because cache file name is empty!";
- return;
- }
+ else if (CacheFile == DO_NOT_USE_CACHE_FILE)
+ GlobalLogger.info() << "DnsCache: configured not to use cache file";
else if ( !I2n::file_exists(CacheFile) )
- {
GlobalLogger.warning() << "DnsCache: cannot load because cache file "
<< CacheFile << " does not exist!";
- return;
- }
- try
+ else
{
- HostAddressVec cache;
-
- std::ifstream ifs( CacheFile.c_str() );
- boost::archive::xml_iarchive ia(ifs);
+ try
+ {
+ std::ifstream ifs( CacheFile.c_str() );
+ boost::archive::xml_iarchive ia(ifs);
- ia >> boost::serialization::make_nvp("IpCache", cache);
- ia >> boost::serialization::make_nvp("CnameCache", cache);
- GlobalLogger.info() << "DnsCache: loaded from file " << CacheFile;
- }
- catch (boost::archive::archive_exception &exc)
- {
- GlobalLogger.warning() << "DnsCache: archive exception loading from "
- << CacheFile << ": " << exc.what();
- }
- catch (std::exception &exc)
- {
- GlobalLogger.warning() << "DnsCache: exception while loading from "
- << CacheFile << ": " << exc.what();
+ ia & BOOST_SERIALIZATION_NVP(IpCache);
+ ia & BOOST_SERIALIZATION_NVP(CnameCache);
+ GlobalLogger.info() << "DnsCache: loaded from file " << CacheFile;
+ }
+ catch (boost::archive::archive_exception &exc)
+ {
+ GlobalLogger.warning() << "DnsCache: archive exception loading from "
+ << CacheFile << ": " << exc.what();
+ }
+ catch (std::exception &exc)
+ {
+ GlobalLogger.warning() << "DnsCache: exception while loading from "
+ << CacheFile << ": " << exc.what();
+ }
}
}
-void DnsCache::update(const std::string &hostname,
- const HostAddressVec &new_data)
+
+// warn if hostname is empty and remove trailing dot
+std::string DnsCache::key_for_hostname(const std::string &hostname) const
{
- GlobalLogger.info() << "DnsCache: update IPs for " << hostname
- << " to " << new_data.size() << "-list";
- IpCache[hostname] = new_data;
- HasChanged = true;
+ if (hostname.empty())
+ {
+ GlobalLogger.warning() << "DnsCache: empty host!";
+ return "";
+ }
+
+ // check whether last character is a dot
+ if (hostname.rfind('.') == hostname.length()-1)
+ return hostname.substr(0, hostname.length()-1);
+ else
+ return hostname;
}
void DnsCache::update(const std::string &hostname,
- const Cname &cname)
+ const HostAddressVec &new_ips)
{
- GlobalLogger.info() << "DnsCache: update CNAME for " << hostname
- << " to " << cname.Host;
- CnameCache[hostname] = cname;
+ std::string key = key_for_hostname(hostname);
+ if ( !get_cname(hostname).Host.empty() )
+ { // ensure that there is never IP and CNAME for the same host
+ GlobalLogger.warning() << "DnsCache: Saving IPs for " << key
+ << " removes CNAME to " << get_cname(hostname).Host << "!";
+ update(hostname, Cname()); // overwrite with "empty" cname
+ }
+ GlobalLogger.debug() << "DnsCache: update IPs for " << key
+ << " to " << new_ips.size() << "-list";
+ IpCache[key] = new_ips;
HasChanged = true;
}
void DnsCache::update(const std::string &hostname,
- const uint32_t new_ttl)
+ const Cname &cname)
{
- GlobalLogger.info() << "DnsCache: ensure TTL for IPs for " << hostname
- << " is below " << new_ttl << "s";
- HostAddressVec ips = IpCache[hostname];
- TimeToLive current_ttl;
- BOOST_FOREACH( HostAddress &addr, ips )
- {
- current_ttl = addr.get_ttl();
- if (current_ttl.get_value() > new_ttl)
- {
- current_ttl.set_value(new_ttl);
- addr.set_ttl(current_ttl);
- HasChanged = true;
- }
+ std::string key = key_for_hostname(hostname);
+ if ( !get_ips(hostname).empty() )
+ { // ensure that there is never IP and CNAME for the same host
+ GlobalLogger.warning() << "DnsCache: Saving CNAME for " << key
+ << " removes " << get_ips(hostname).size() << " IPs for same host!";
+ update(hostname, HostAddressVec()); // overwrite with empty IP list
}
- IpCache[hostname] = ips;
+
+ // remove possible trailing dot from cname
+ Cname to_save = Cname(key_for_hostname(cname.Host),
+ cname.Ttl);
+
+ GlobalLogger.info() << "DnsCache: update CNAME for " << key
+ << " to " << to_save.Host;
+ CnameCache[key] = to_save;
+ HasChanged = true;
}
HostAddressVec DnsCache::get_ips(const std::string &hostname,
const bool check_up_to_date)
{
- HostAddressVec result = IpCache[hostname];
+ std::string key = key_for_hostname(hostname);
+ HostAddressVec result = IpCache[key];
if (check_up_to_date)
{
HostAddressVec result_up_to_date;
uint32_t threshold = static_cast<uint32_t>(
DnsMaster::get_instance()->get_resolved_ip_ttl_threshold() );
+ uint32_t updated_ttl;
BOOST_FOREACH( const HostAddress &addr, result )
{
- if (addr.get_ttl().get_updated_value() > threshold)
+ updated_ttl = addr.get_ttl().get_updated_value();
+ if (updated_ttl > threshold)
result_up_to_date.push_back(addr);
+ else
+ GlobalLogger.debug() << "DnsCache: do not return "
+ << addr.get_ip().to_string() << " since TTL "
+ << updated_ttl << "s is out of date (thresh="
+ << threshold << "s)";
}
- 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
- << " --> " << result.size() << "-list";
+ GlobalLogger.debug() << "DnsCache: request IPs for " << key
+ << " --> " << result.size() << "-list";
+ BOOST_FOREACH( const HostAddress &addr, result )
+ GlobalLogger.debug() << "DnsCache: " << addr.get_ip().to_string()
+ << " (TTL " << addr.get_ttl().get_value() << "s)";
return result;
}
Cname 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
- << " --> \"" << result_obj.Host << "\"";
+ std::string key = key_for_hostname(hostname);
+ Cname result_obj = CnameCache[key];
+ GlobalLogger.debug() << "DnsCache: request CNAME for " << key
+ << " --> \"" << result_obj.Host << "\"";
if (result_obj.Host.empty())
return result_obj;
else if (check_up_to_date)
{
- if (result_obj.Ttl.get_updated_value() > DnsMaster::get_instance()
- ->get_resolved_ip_ttl_threshold())
+ if ( result_obj.Ttl.get_updated_value() > static_cast<uint32_t>(
+ DnsMaster::get_instance()->get_resolved_ip_ttl_threshold()) )
return result_obj;
else
{
while ( result.empty() )
{
current_cname = get_cname(current_host, check_up_to_date);
- current_host = current_cname.Host;
+ current_host = key_for_hostname(current_cname.Host);
if (current_host.empty())
break;
else if (++n_recursions >= Config::MaxRetrievalRecursions)
}
cname = get_cname(up_to_date_host);
- if (cname.Host.empty())
+ if (key_for_hostname(cname.Host).empty())
// reached end of cname list
break;
else if (cname.Ttl.get_updated_value() > ttl_thresh)