added option min-time-between-resolves-option and tests for it
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Mon, 4 May 2015 08:47:53 +0000 (10:47 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Mon, 4 May 2015 14:57:59 +0000 (16:57 +0200)
16 files changed:
src/CMakeLists.txt
src/config/configuration.cpp
src/config/configuration.h
src/config/configurationoptions.cpp
src/config/option/mintimebetweenresolvesoption.cpp [new file with mode: 0644]
src/config/option/mintimebetweenresolvesoption.h [new file with mode: 0644]
src/dns/dnscache.cpp
src/dns/dnscache.h
src/dns/dnsmaster.cpp
src/dns/dnsmaster.h
src/main.cpp
test/CMakeLists.test_configurationcommandline.txt
test/CMakeLists.test_configurationfile.txt
test/CMakeLists.test_configurationoptions.txt
test/test_configurationoptions.cpp
test/test_dns.cpp

index 68ab5db..efed741 100644 (file)
@@ -59,6 +59,7 @@ set(SOURCES
     config/option/pingreplytimeoutoption.cpp
     config/option/maxaddressresolutionattemptsoption.cpp
     config/option/resolvedipttlthresholdoption.cpp
+    config/option/mintimebetweenresolvesoption.cpp
     config/option/dnscachefileoption.cpp
     dns/timetolive.cpp
     dns/hostaddress.cpp
index 48971fd..c030e81 100644 (file)
@@ -62,6 +62,7 @@ Configuration::Configuration() :
     PingReplyTimeout( 30 ),
     MaxAddressResolutionAttempts( 10 ),
     ResolvedIpTtlThreshold( 10 ),
+    MinTimeBetweenResolves( 10 ),
     DnsCacheFile(""),
     Hosts(),
     RatioRandomHosts( 1.0f ),
@@ -248,6 +249,16 @@ void Configuration::set_resolved_ip_ttl_threshold( const int resolved_ip_ttl_thr
     ResolvedIpTtlThreshold = resolved_ip_ttl_threshold;
 }
 
+int Configuration::get_min_time_between_resolves() const
+{
+    return MinTimeBetweenResolves;
+}
+void Configuration::set_min_time_between_resolves( const int min_time_between_resolves )
+{
+    BOOST_ASSERT(min_time_between_resolves >= 0 );
+    MinTimeBetweenResolves = min_time_between_resolves;
+}
+
 void Configuration::set_dns_cache_file( const std::string &dns_cache_file)
 {
     BOOST_ASSERT( !dns_cache_file.empty() );
index ca0c5a7..32e9d13 100644 (file)
@@ -98,6 +98,10 @@ public:
     void set_resolved_ip_ttl_threshold(
             const int resolved_ip_ttl_threshold );
 
+    int get_min_time_between_resolves() const;
+    void set_min_time_between_resolves(
+            const int min_time_between_resolves );
+
     std::string get_dns_cache_file() const;
     void set_dns_cache_file(const std::string &dns_cache_file);
 
@@ -136,6 +140,7 @@ private:
     int PingReplyTimeout;
     int MaxAddressResolutionAttempts;
     int ResolvedIpTtlThreshold;
+    int MinTimeBetweenResolves;
     std::string DnsCacheFile;
     HostList Hosts;
     float RatioRandomHosts;
index 3c975eb..9e574dd 100644 (file)
@@ -49,6 +49,7 @@
 #include "config/option/pingreplytimeoutoption.h"
 #include "config/option/maxaddressresolutionattemptsoption.h"
 #include "config/option/resolvedipttlthresholdoption.h"
+#include "config/option/mintimebetweenresolvesoption.h"
 #include "config/option/dnscachefileoption.h"
 
 using namespace std;
@@ -121,6 +122,9 @@ ConfigurationOptions::ConfigurationOptions() :
     ConfigurationOptionItem resolved_ip_ttl_threshold( new ResolvedIpTtlThresholdOption );
     ConfigOptions.push_back( resolved_ip_ttl_threshold );
 
+    ConfigurationOptionItem min_time_between_resolves( new MinTimeBetweenResolvesOption );
+    ConfigOptions.push_back( min_time_between_resolves );
+
     ConfigurationOptionItem ratio_random_hosts( new RatioRandomHostsOption );
     ConfigOptions.push_back( ratio_random_hosts );
 
diff --git a/src/config/option/mintimebetweenresolvesoption.cpp b/src/config/option/mintimebetweenresolvesoption.cpp
new file mode 100644 (file)
index 0000000..2f279fa
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ 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.
+ */
+
+#include "config/option/mintimebetweenresolvesoption.h"
+
+#include <logfunc.hpp>
+
+using namespace std;
+using boost::program_options::value;
+using boost::program_options::variables_map;
+using I2n::Logger::GlobalLogger;
+
+//-----------------------------------------------------------------------------
+// MinTimeBetweenResolvesOption
+//-----------------------------------------------------------------------------
+
+MinTimeBetweenResolvesOption::MinTimeBetweenResolvesOption() :
+    ConfigurationOption(
+        "min-time-between-resolves",
+        value<int>()->default_value( 10 ),
+        "Minimum time in seconds between calls to DNS resolve of same address"
+    )
+{
+}
+
+MinTimeBetweenResolvesOption::~MinTimeBetweenResolvesOption()
+{
+}
+
+bool MinTimeBetweenResolvesOption::parse(
+        const variables_map& vm,
+        Configuration *configuration
+)
+{
+    // default-source-network-interface
+    if ( 1 <= vm.count( get_command_string() ) )
+    {
+        int thresh = vm[ get_command_string() ].as<int> ();
+        configuration->set_min_time_between_resolves( thresh );
+
+        GlobalLogger.info() << get_command_string() << "="
+                << thresh << endl;
+
+        return true;
+    }
+
+    return false;
+}
diff --git a/src/config/option/mintimebetweenresolvesoption.h b/src/config/option/mintimebetweenresolvesoption.h
new file mode 100644 (file)
index 0000000..4ab1f71
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ 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.
+ */
+
+#ifndef MIN_TIME_BETWEEN_RESOLVES_OPTION_H
+#define MIN_TIME_BETWEEN_RESOLVES_OPTION_H
+
+#include <boost/program_options.hpp>
+
+#include "config/option/configurationoption.h"
+
+//-----------------------------------------------------------------------------
+// MinTimeBetweenResolvesOption
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief This class represents the "min-time-between-resolves"
+ * configuration option.
+ */
+class MinTimeBetweenResolvesOption : public ConfigurationOption
+{
+public:
+    MinTimeBetweenResolvesOption();
+    virtual ~MinTimeBetweenResolvesOption();
+
+    virtual bool parse(
+            const boost::program_options::variables_map &vm,
+            Configuration *configuration
+    );
+
+};
+
+#endif // MIN_TIME_BETWEEN_RESOLVES_OPTION_H
index c79ef83..4c524e7 100644 (file)
@@ -49,6 +49,10 @@ namespace Config
     int MaxRetrievalRecursions = 10;
 }
 
+// -----------------------------------------------------------------------------
+// Cname
+// -----------------------------------------------------------------------------
+
 Cname::Cname()
     : Host()
     , Ttl()
@@ -65,15 +69,21 @@ Cname::Cname(const std::string &host, const TimeToLive &ttl)
 {}
 
 
+// -----------------------------------------------------------------------------
+// DNS Cache constructor / destructor
+// -----------------------------------------------------------------------------
+
 const string DnsCache::DoNotUseCacheFile = "do not use cache file!";
 
 DnsCache::DnsCache(const IoServiceItem &io_serv,
-                   const std::string &cache_file)
+                   const std::string &cache_file,
+                   const uint32_t min_time_between_resolves)
     : IpCache()
     , CnameCache()
     , SaveTimer( *io_serv )
     , CacheFile( cache_file )
     , HasChanged( false )
+    , MinTimeBetweenResolves( min_time_between_resolves )
 {
     // load cache from file
     load_from_cachefile();
@@ -97,6 +107,10 @@ DnsCache::~DnsCache()
 }
 
 
+// -----------------------------------------------------------------------------
+// LOAD / SAVE
+// -----------------------------------------------------------------------------
+
 void DnsCache::schedule_save(const boost::system::error_code &error)
 {
     // just in case: ensure SaveTimer is cancelled
@@ -190,6 +204,10 @@ void DnsCache::load_from_cachefile()
 }
 
 
+// -----------------------------------------------------------------------------
+// UPDATE
+// -----------------------------------------------------------------------------
+
 // warn if hostname is empty and remove trailing dot
 std::string DnsCache::key_for_hostname(const std::string &hostname) const
 {
@@ -217,9 +235,26 @@ void DnsCache::update(const std::string &hostname,
             << " removes CNAME to " << get_cname(hostname).Host << "!";
         update(hostname, Cname());   // overwrite with "empty" cname
     }
+    // ensure min ttl of MinTimeBetweenResolves
+    HostAddressVec ips_checked;
+    BOOST_FOREACH( const HostAddress &addr, new_ips )
+    {
+        if ( addr.get_ttl().get_value() < MinTimeBetweenResolves )
+        {
+            GlobalLogger.info() << "DnsCache: Correcting TTL of IP for "
+                << hostname << " from " << addr.get_ttl().get_value() << "s to "
+                << MinTimeBetweenResolves << "s because was too short";
+            ips_checked.push_back( HostAddress( addr.get_ip(),
+                                                MinTimeBetweenResolves) );
+        }
+        else
+            ips_checked.push_back(addr);
+    }
+
     GlobalLogger.info() << "DnsCache: update IPs for " << key
-                        << " to " << new_ips.size() << "-list";
-    IpCache[key] = new_ips;
+                        << " to " << ips_checked.size() << "-list";
+
+    IpCache[key] = ips_checked;
     HasChanged = true;
 }
 
@@ -239,6 +274,15 @@ void DnsCache::update(const std::string &hostname,
     Cname to_save = Cname(key_for_hostname(cname.Host),
                           cname.Ttl);
 
+    // ensure min ttl of MinTimeBetweenResolves
+    if ( to_save.Ttl.get_value() < MinTimeBetweenResolves )
+    {
+        GlobalLogger.info() << "DnsCache: Correcting TTL of CNAME of "
+            << hostname << " from " << to_save.Ttl.get_value() << "s to "
+            << MinTimeBetweenResolves << "s because was too short";
+        to_save.Ttl = TimeToLive(MinTimeBetweenResolves);
+    }
+
     GlobalLogger.info() << "DnsCache: update CNAME for " << key
                         << " to " << to_save.Host;
     CnameCache[key] = to_save;
@@ -246,6 +290,10 @@ void DnsCache::update(const std::string &hostname,
 }
 
 
+// -----------------------------------------------------------------------------
+// RETRIEVAL
+// -----------------------------------------------------------------------------
+
 /**
  * @returns empty list if no (up to date) ips for hostname in cache
  */
index 3bc1758..c165c0d 100644 (file)
@@ -51,7 +51,8 @@ public:
     static const std::string DoNotUseCacheFile;
 
     DnsCache( const IoServiceItem &io_serv,
-              const std::string &cache_file );
+              const std::string &cache_file,
+              const uint32_t min_time_between_resolves );
     ~DnsCache();
 
     // accessed from ResolverBase subclasses
@@ -75,6 +76,7 @@ private:
     boost::asio::deadline_timer SaveTimer;
     std::string CacheFile;
     bool HasChanged;
+    uint32_t MinTimeBetweenResolves;
 
 // internal functions
 private:
index f25f09c..7235a1e 100644 (file)
@@ -39,13 +39,22 @@ DnsMasterItem DnsMaster::TheOnlyInstance;
 void DnsMaster::create_master(const IoServiceItem &io_serv,
                             const boost::asio::ip::address &default_name_server,
                             const int resolved_ip_ttl_threshold,
+                            const int min_time_between_resolves,
                             const int max_address_resolution_attempts,
                             const std::string &cache_file)
 {
     GlobalLogger.info() << "DnsMaster: Creating cache";
-    DnsCacheItem cache( new DnsCache(io_serv, cache_file) );
-    create_master(io_serv, default_name_server, resolved_ip_ttl_threshold,
-                  max_address_resolution_attempts, cache);
+    DnsCacheItem cache(
+            new DnsCache(io_serv,
+                         cache_file,
+                         static_cast<uint32_t>(min_time_between_resolves)
+            )
+        );
+    create_master(io_serv,
+                  default_name_server,
+                  resolved_ip_ttl_threshold,
+                  max_address_resolution_attempts,
+                  cache);
 }
 
 void DnsMaster::create_master(const IoServiceItem &io_serv,
index 1976ba5..424d8ba 100644 (file)
@@ -100,6 +100,7 @@ public:
     static void create_master(const IoServiceItem &io_serv,
                             const boost::asio::ip::address &default_name_server,
                             const int resolved_ip_ttl_threshold,
+                            const int min_time_between_resolves,
                             const int max_address_resolution_attempts,
                             const std::string &cache_file);
     static void create_master(const IoServiceItem &io_serv,
index 1463001..5fffb50 100644 (file)
@@ -517,6 +517,7 @@ int main( int argc, const char *argv[] )
                            io_service,
                            name_server_ip,
                            configuration->get_resolved_ip_ttl_threshold(),
+                           configuration->get_min_time_between_resolves(),
                            configuration->get_max_address_resolution_attempts(),
                            configuration->get_dns_cache_file() );
 
index 589996c..b8788eb 100644 (file)
@@ -31,6 +31,7 @@ add_executable(test_configurationcommandline
     ${CMAKE_SOURCE_DIR}/src/config/option/pingreplytimeoutoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/maxaddressresolutionattemptsoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/resolvedipttlthresholdoption.cpp
+    ${CMAKE_SOURCE_DIR}/src/config/option/mintimebetweenresolvesoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/dnscachefileoption.cpp
     ${CMAKE_SOURCE_DIR}/src/host/loglevel.cpp
     ${CMAKE_SOURCE_DIR}/src/host/logoutput.cpp
index a3fa1f7..522a18b 100644 (file)
@@ -31,6 +31,7 @@ add_executable(test_configurationfile
     ${CMAKE_SOURCE_DIR}/src/config/option/pingreplytimeoutoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/maxaddressresolutionattemptsoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/resolvedipttlthresholdoption.cpp
+    ${CMAKE_SOURCE_DIR}/src/config/option/mintimebetweenresolvesoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/dnscachefileoption.cpp
     ${CMAKE_SOURCE_DIR}/src/host/loglevel.cpp
     ${CMAKE_SOURCE_DIR}/src/host/logoutput.cpp
index b96956c..f2fea82 100644 (file)
@@ -29,6 +29,7 @@ add_executable(test_configurationoptions
     ${CMAKE_SOURCE_DIR}/src/config/option/pingreplytimeoutoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/maxaddressresolutionattemptsoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/resolvedipttlthresholdoption.cpp
+    ${CMAKE_SOURCE_DIR}/src/config/option/mintimebetweenresolvesoption.cpp
     ${CMAKE_SOURCE_DIR}/src/config/option/dnscachefileoption.cpp
     ${CMAKE_SOURCE_DIR}/src/host/loglevel.cpp
     ${CMAKE_SOURCE_DIR}/src/host/logoutput.cpp
index 86463bc..bf4e418 100644 (file)
@@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE( get_configuration_options )
     // if this assert fails, you must add or remove one of the options in the
     // test below. Will probably find them all in
     // src/config/configurationoptions.cpp constructor
-    BOOST_CHECK_EQUAL( options.size(), 17 );
+    BOOST_CHECK_EQUAL( options.size(), 18 );
 
     BOOST_CHECK_EQUAL( option_present( options, "hosts-down-limit" ), true );
     BOOST_CHECK_EQUAL( option_present( options, "link-down-interval" ), true );
@@ -136,6 +136,7 @@ BOOST_AUTO_TEST_CASE( get_configuration_options )
     BOOST_CHECK_EQUAL( option_present( options, "ping-reply-timeout" ), true );
     BOOST_CHECK_EQUAL( option_present( options, "max-address-resolution-attempts" ), true );
     BOOST_CHECK_EQUAL( option_present( options, "resolved-ip-ttl-threshold" ), true );
+    BOOST_CHECK_EQUAL( option_present( options, "min-time-between-resolves" ), true );
     BOOST_CHECK_EQUAL( option_present( options, "dns-cache-file" ), true );
     BOOST_CHECK_EQUAL( option_present( options, "ratio-random-hosts" ), true );
     BOOST_CHECK_EQUAL( option_present( options, "host.name" ), true );
index 9c95577..8273aee 100644 (file)
@@ -45,7 +45,8 @@ using boost::asio::ip::address;
 
 // constants for master
 address name_server = address::from_string("127.0.0.1");
-int resolved_ip_ttl_threshold = 3;
+int resolved_ip_ttl_threshold = 5;
+uint32_t min_time_between_resolves = 3; // should be < resolved_ip_ttl_threshold
 int max_address_resolution_attempts = 2;
 std::string cache_file = DnsCache::DoNotUseCacheFile;
 
@@ -76,7 +77,7 @@ struct GlobalFixture
 
         // DNS Cache
         DnsCacheItem cache_temp = DnsCacheItem(
-                                          new DnsCache(IoService, cache_file) );
+               new DnsCache(IoService, cache_file, min_time_between_resolves) );
         cache_temp.swap( Cache );
         cache_temp.reset();
         fill_cache();
@@ -132,7 +133,7 @@ struct GlobalFixture
             Cache->update("cname3.test", Cname("cname2.test", 37) );
         }
 
-        {
+        {   // for cache_outdated_test
             HostAddressVec ips;
             ips.push_back( HostAddress( address::from_string("192.168.42.4"),
                                         0 ) );
@@ -150,6 +151,17 @@ struct GlobalFixture
                       Cname("host_outdated.test", resolved_ip_ttl_threshold+1));
         }
 
+        {   // for cache_ttl_below_thresh_test
+            // TTLs < min_time_between_resolves should be corrected
+            HostAddressVec ips;
+            ips.push_back( HostAddress( address::from_string("192.128.42.8"),
+                                        1 ) );
+            Cache->update("host_ttl_below_thresh.test", ips);
+
+            Cache->update( "cname_ttl_below_thresh.test",
+                      Cname("host_ttl_below_thresh.test", 2) );
+        }
+
         BOOST_TEST_MESSAGE( "Done filling cache." );
     }
 
@@ -211,7 +223,7 @@ BOOST_FIXTURE_TEST_SUITE( TestDnsCache, TestFixture )
 BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
 {
     HostAddressVec ips = Cache->get_ips("host1.test");
-    BOOST_CHECK_EQUAL( ips.size(), 1 );
+    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK( ip.is_valid() );
     BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
@@ -247,7 +259,7 @@ BOOST_AUTO_TEST_CASE( cache_retrieve_recursive1 )
 {
     // should get IP from host1 but ttl from cname since is smaller
     HostAddressVec ips = Cache->get_ips_recursive("cname.test");
-    BOOST_CHECK_EQUAL( ips.size(), 1 );
+    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK( ip.is_valid() );
     BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
@@ -258,7 +270,7 @@ BOOST_AUTO_TEST_CASE( cache_retrieve_recursive2 )
 {
     // should get IP from host1 but ttl from cname2 since is smaller
     HostAddressVec ips = Cache->get_ips_recursive("cname3.test");
-    BOOST_CHECK_EQUAL( ips.size(), 1 );
+    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK( ip.is_valid() );
     BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
@@ -331,9 +343,11 @@ BOOST_AUTO_TEST_CASE( cache_load_test )
     std::stringstream file_name;
     file_name << DATA_DIR_STRING << "/" << "dns_cache_example.xml";
     BOOST_TEST_MESSAGE( "loading cache from file " << file_name.str() );
-    DnsCache loaded_cache( IoService, file_name.str() );
+    DnsCache loaded_cache( IoService,
+                           file_name.str(),
+                           min_time_between_resolves );
     HostAddressVec ips = loaded_cache.get_ips("abc.xyz");
-    BOOST_CHECK_EQUAL( ips.size(), 1 );
+    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "11.22.33.44" );
     BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 567 );
@@ -374,7 +388,17 @@ BOOST_AUTO_TEST_CASE( cache_outdated_test )
     BOOST_CHECK_EQUAL( ips.size(), 1 );
 }
 
+BOOST_AUTO_TEST_CASE( cache_ttl_below_thresh_test )
+{
+    // in fill_cache, 
+    HostAddressVec ips = Cache->get_ips("host_ttl_below_thresh.test", false);
+    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
+    HostAddress ip = ips.front();
+    BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), min_time_between_resolves );
 
+    Cname cname = Cache->get_cname("cname_ttl_below_thresh.test", false);
+    BOOST_CHECK_EQUAL( cname.Ttl.get_value(), min_time_between_resolves );
+}
 
 BOOST_AUTO_TEST_SUITE_END()    // of TestDnsCache