From: Christian Herdtweck Date: Thu, 23 Apr 2015 16:06:45 +0000 (+0200) Subject: simplified dns (no self-made recursion); merge PingScheduler and PingRotate; make... X-Git-Url: http://developer.intra2net.com/git/?p=pingcheck;a=commitdiff_plain;h=23f51766fcfbacbf62054868b8ab32841366f218 simplified dns (no self-made recursion); merge PingScheduler and PingRotate; make them use Async DNS does not compile yet, work in progress! --- diff --git a/doc/pingcheck_icmp_distributor.graphml b/doc/pingcheck_icmp_distributor.graphml index d6248fc..bca452a 100644 --- a/doc/pingcheck_icmp_distributor.graphml +++ b/doc/pingcheck_icmp_distributor.graphml @@ -14,150 +14,13 @@ - - - - - - - IcmpPinger - - - - - - - - - - - - - - - - - IcmpPinger - - - - - - - - - - - - - - - - - IcmpPacketDistributor -(singleton) - - - - - - - - - - - - - - - - - PingerFactory - - - - - - - - - - - - - - - - - IcmpPacketFactory - - - - - - - - - - - - - - - - - ICMP -Socket - - - - - - - - - - - - - - - - - the world - - - - - - - - - - - - - - - - NetworkInterface - - - - - - - - - - - + - + - Time Course + Time Course main @@ -165,7 +28,7 @@ Socket - PingScheduler (+timer) + PingScheduler (+timer) @@ -200,7 +63,7 @@ Socket - other components + other components @@ -218,13 +81,13 @@ Socket - + - + @@ -242,7 +105,7 @@ Socket - + @@ -254,11 +117,11 @@ Socket - - + + - + start_pinging @@ -272,30 +135,13 @@ Socket - - - - - - - resolve_and_ping - - - - - - - - - - - + - + - ping + ping @@ -306,10 +152,10 @@ Socket - + - + main @@ -323,10 +169,10 @@ Socket - + - + start_pingers @@ -340,10 +186,10 @@ Socket - + - + ping_done_handler @@ -357,10 +203,10 @@ Socket - + - + First Delay @@ -374,10 +220,10 @@ Socket - + - + async_wait @@ -391,10 +237,10 @@ Socket - + - + update_ping_interval @@ -408,10 +254,10 @@ Socket - + - + update_ping_elapsed_time @@ -425,10 +271,10 @@ Socket - + - + init_pingers @@ -442,10 +288,10 @@ Socket - + - + Constructor @@ -459,62 +305,11 @@ Socket - + - - - - Constructor - - - - - - - - - - - - - - - - - ping - - - - - - - - - - - - - - - - - set_ping_done_callback - - - - - - - - - - - - - - - + + update_ping_protocol @@ -527,11 +322,11 @@ Socket - + - - + + get_next_ping_protocol @@ -544,10 +339,10 @@ Socket - + - + timeout @@ -562,10 +357,10 @@ PingIntervalInSec - + - + stop_pingers @@ -579,10 +374,10 @@ PingIntervalInSec - + - + stop_pinging @@ -596,10 +391,10 @@ PingIntervalInSec - + - + main @@ -613,27 +408,10 @@ PingIntervalInSec - - - - - - - stop_pinging - - - - - - - - - - - + - + cancel @@ -647,10 +425,10 @@ PingIntervalInSec - + - + ping_done_handler @@ -664,10 +442,10 @@ PingIntervalInSec - + - + ... @@ -681,10 +459,10 @@ PingIntervalInSec - + - + get_socket @@ -698,10 +476,10 @@ PingIntervalInSec - + - + register_receive_handler @@ -715,10 +493,10 @@ PingIntervalInSec - + - + async_receive @@ -732,10 +510,10 @@ PingIntervalInSec - + - + send_to @@ -749,10 +527,10 @@ PingIntervalInSec - + - + handle_receive @@ -766,10 +544,10 @@ PingIntervalInSec - + - + register_receive_handler @@ -783,10 +561,10 @@ PingIntervalInSec - + - + IcmpPacketFactory @@ -801,10 +579,10 @@ PingIntervalInSec - + - + IcmpPacketFactory @@ -819,10 +597,10 @@ PingIntervalInSec - + - + HostStatus @@ -837,10 +615,10 @@ PingIntervalInSec - + - + async_receive @@ -854,28 +632,10 @@ PingIntervalInSec - + - - - - Pingerfactory -::createPinger - - - - - - - - - - - - - - + PingerFactory @@ -890,10 +650,10 @@ PingIntervalInSec - + - + ping @@ -907,10 +667,10 @@ PingIntervalInSec - + - + start_send @@ -924,10 +684,10 @@ PingIntervalInSec - + - + send_echo_request @@ -941,10 +701,10 @@ PingIntervalInSec - + - + schedule_timeout_echo_reply @@ -958,10 +718,10 @@ PingIntervalInSec - + - + handle_receive_icmp_packet @@ -975,10 +735,10 @@ PingIntervalInSec - + - + set_ping_status @@ -992,10 +752,10 @@ PingIntervalInSec - + - + set_ping_status @@ -1009,10 +769,10 @@ PingIntervalInSec - + - + PingDoneCallback @@ -1026,10 +786,10 @@ PingIntervalInSec - + - + async_wait @@ -1043,10 +803,10 @@ PingIntervalInSec - + - + cancel @@ -1060,10 +820,10 @@ PingIntervalInSec - + - + handle_timeout @@ -1077,10 +837,10 @@ PingIntervalInSec - + - + set_ping_status @@ -1094,10 +854,10 @@ PingIntervalInSec - + - + Constructor @@ -1111,10 +871,10 @@ PingIntervalInSec - + - + EchoReplyTimeout @@ -1128,10 +888,10 @@ PingIntervalInSec - + - + create (static) @@ -1145,10 +905,10 @@ PingIntervalInSec - + - + get_distributor (static) @@ -1162,10 +922,10 @@ PingIntervalInSec - + - + Constructor @@ -1179,10 +939,10 @@ PingIntervalInSec - + - + Constructor @@ -1196,10 +956,10 @@ PingIntervalInSec - + - + register_pinger @@ -1213,10 +973,10 @@ PingIntervalInSec - + - + clean_up_all (static) @@ -1230,10 +990,10 @@ PingIntervalInSec - + - + stop_pinging @@ -1247,10 +1007,10 @@ PingIntervalInSec - + - + unregister_pinger @@ -1264,10 +1024,10 @@ PingIntervalInSec - + - + clean_up @@ -1281,10 +1041,10 @@ PingIntervalInSec - + - + close @@ -1298,10 +1058,10 @@ PingIntervalInSec - + - + cancel @@ -1315,10 +1075,10 @@ PingIntervalInSec - + - + handle_timeout @@ -1332,10 +1092,10 @@ PingIntervalInSec - + - + ... @@ -1349,10 +1109,10 @@ PingIntervalInSec - + - + ... @@ -1366,10 +1126,10 @@ PingIntervalInSec - + - + ... @@ -1383,13 +1143,15 @@ PingIntervalInSec - + - - + + - DNS timer + HostStatus +::set_resovled_ip_count +::report_dns_resolution_failure @@ -1400,15 +1162,14 @@ PingIntervalInSec - + - + - HostStatus -::set_resovled_ip_count -::report_dns_resolution_failure + HostStatus +::exceeded_ping_failed_limit @@ -1419,14 +1180,13 @@ PingIntervalInSec - + - - + + - HostStatus -::exceeded_ping_failed_limit + init_ping_protocol @@ -1437,13 +1197,14 @@ PingIntervalInSec - + - - + + - init_ping_protocol + get_next_ping_protocol +... (see above) ... @@ -1454,14 +1215,13 @@ PingIntervalInSec - + - - + + - get_next_ping_protocol -... (see above) ... + update_dns_resolver @@ -1472,13 +1232,14 @@ PingIntervalInSec - + - - + + - update_dns_resolver + DnsMaster:: +get_resolver_for @@ -1489,14 +1250,14 @@ PingIntervalInSec - + - - + + - DnsResolverFactory -::createResolver + start_resolving +_ping_address @@ -1507,13 +1268,14 @@ PingIntervalInSec - + - - + + - resolve_ping_address + DnsReesolver +::async_resolve @@ -1524,14 +1286,13 @@ PingIntervalInSec - + - + - DnsReesolver -::resolve + get_resolved_ip_count @@ -1542,13 +1303,13 @@ PingIntervalInSec - + - - + + - resolve_ping_address + ... @@ -1559,13 +1320,14 @@ PingIntervalInSec - + - - + + - get_resolved_ip_count + PingerFactory +::createPinger @@ -1576,13 +1338,13 @@ PingIntervalInSec - + - - + + - have_up_to_date_ip + ... @@ -1593,14 +1355,13 @@ PingIntervalInSec - + - - + + - DnsReesolver -::resolve + ... @@ -1611,13 +1372,13 @@ PingIntervalInSec - + - + - have_up_to_date_ip + ... @@ -1628,13 +1389,13 @@ PingIntervalInSec - + - - + + - get_resolved_ip_count + ... @@ -1645,14 +1406,15 @@ PingIntervalInSec - + + - + - DnsResolver -::get_next_ip + DnsResolver +::finalize_resolve @@ -1663,13 +1425,14 @@ PingIntervalInSec - + + - + - ... + dns_resolve_callback @@ -1680,14 +1443,14 @@ PingIntervalInSec - + + - - + + - PingerFactory -::createPinger + try_to_ping @@ -1698,13 +1461,14 @@ PingIntervalInSec - + + - - + + - ... + try_to_ping @@ -1715,29 +1479,157 @@ PingIntervalInSec - + + - - + + - ... + when +both +finished - + - + + - + + DnsResolver +::have_up_to_date_ips + + + + + + + + + + + + + + + + + + have +IPs? + + + + + + + + + + + + + + + + + get IP + + + + + + + + + + + + + + + + send request +receive echo reply +or destin. unreach + + + + + + + + + + + + + + + + no reply + + + + + + + + + + + + + + + + + OR + + + + + + + + + + + + + + + + + + success? + + + + + + + + + + + + + + + + + ... @@ -1745,15 +1637,35 @@ PingIntervalInSec + + + + + + + + + + + + DnsResolver +::get_next_ip + + + + + + - + + - - + + ... @@ -1762,19 +1674,94 @@ PingIntervalInSec + + + + + + + + + + + + DnsResolver +::get_skipper + + + + + + + + + + + + + + + + + + try_to_ping + + + + + + + + + + + + + + DnsResolver:: +cancel_resolve + + + + + + + + + + + + + + + + + + SIGTERM +SIGKILL + + + + + + + + + + - + - - + + - deadline_timer + IcmpPinger @@ -1785,13 +1772,13 @@ PingIntervalInSec - + - - + + - deadline_timer + IcmpPinger @@ -1802,13 +1789,14 @@ PingIntervalInSec - + - - + + - PingScheduler + IcmpPacketDistributor +(singleton) @@ -1819,13 +1807,13 @@ PingIntervalInSec - + - - + + - PingScheduler + PingerFactory @@ -1836,10 +1824,78 @@ PingIntervalInSec - + - + + + + IcmpPacketFactory + + + + + + + + + + + + + + + + + ICMP +Socket + + + + + + + + + + + + + + + + + the world + + + + + + + + + + + + + + + + NetworkInterface + + + + + + + + + + + + + + deadline_timer @@ -1853,10 +1909,10 @@ PingIntervalInSec - + - + deadline_timer @@ -1870,13 +1926,13 @@ PingIntervalInSec - + - - + + - PingRotate + PingScheduler @@ -1887,13 +1943,13 @@ PingIntervalInSec - + - - + + - PingRotate + PingScheduler @@ -1904,30 +1960,30 @@ PingIntervalInSec - + - - + + - OR + deadline_timer - + - + - - - - ... + + + + deadline_timer @@ -1938,59 +1994,58 @@ PingIntervalInSec - + - - - + + + - send request -receive echo reply -or destin. unreachable + PingRotate - + + - + - - - + + + - no reply + PingRotate - + + - + - + - - SIGTERM -SIGKILL + + ... - + - + @@ -2007,7 +2062,7 @@ SIGKILL - + @@ -2024,7 +2079,7 @@ SIGKILL - + @@ -2042,7 +2097,7 @@ shared_ptrs - + @@ -2051,7 +2106,7 @@ shared_ptrs - + @@ -2068,7 +2123,7 @@ shared_ptrs - + @@ -2077,7 +2132,7 @@ shared_ptrs - + @@ -2094,7 +2149,7 @@ shared_ptrs - + @@ -2103,7 +2158,7 @@ shared_ptrs - + @@ -2112,7 +2167,7 @@ shared_ptrs - + @@ -2129,7 +2184,7 @@ shared_ptrs - + @@ -2138,7 +2193,7 @@ shared_ptrs - + @@ -2155,7 +2210,7 @@ shared_ptrs - + @@ -2172,7 +2227,7 @@ shared_ptrs - + @@ -2189,7 +2244,7 @@ shared_ptrs - + @@ -2206,16 +2261,7 @@ shared_ptrs - - - - - - - - - - + @@ -2224,7 +2270,7 @@ shared_ptrs - + @@ -2233,7 +2279,7 @@ shared_ptrs - + @@ -2242,7 +2288,7 @@ shared_ptrs - + @@ -2310,27 +2356,18 @@ shared_ptrs - - - - - - - - - - + - + - + @@ -2339,7 +2376,7 @@ shared_ptrs - + @@ -2348,7 +2385,7 @@ shared_ptrs - + @@ -2382,25 +2419,7 @@ shared_ptrs - - - - - - - - - - - - - - - - - - - + @@ -2409,29 +2428,20 @@ shared_ptrs - - - - - - - - - - + - - - + + + - + @@ -2440,7 +2450,7 @@ shared_ptrs - + @@ -2449,7 +2459,7 @@ shared_ptrs - + @@ -2458,7 +2468,7 @@ shared_ptrs - + @@ -2467,7 +2477,7 @@ shared_ptrs - + @@ -2476,7 +2486,7 @@ shared_ptrs - + @@ -2485,18 +2495,18 @@ shared_ptrs - + - + - + @@ -2505,13 +2515,13 @@ shared_ptrs - + - IcmpPacket + IcmpPacket @@ -2522,7 +2532,7 @@ shared_ptrs - + @@ -2531,7 +2541,7 @@ shared_ptrs - + @@ -2540,7 +2550,7 @@ shared_ptrs - + @@ -2549,7 +2559,7 @@ shared_ptrs - + @@ -2558,7 +2568,7 @@ shared_ptrs - + @@ -2567,7 +2577,7 @@ shared_ptrs - + @@ -2576,7 +2586,7 @@ shared_ptrs - + @@ -2585,7 +2595,7 @@ shared_ptrs - + @@ -2594,7 +2604,7 @@ shared_ptrs - + @@ -2603,7 +2613,7 @@ shared_ptrs - + @@ -2612,7 +2622,7 @@ shared_ptrs - + @@ -2621,7 +2631,7 @@ shared_ptrs - + @@ -2630,16 +2640,16 @@ shared_ptrs - + - + - + @@ -2648,7 +2658,7 @@ shared_ptrs - + @@ -2657,7 +2667,7 @@ shared_ptrs - + @@ -2666,7 +2676,7 @@ shared_ptrs - + @@ -2675,7 +2685,7 @@ shared_ptrs - + @@ -2684,7 +2694,7 @@ shared_ptrs - + @@ -2693,7 +2703,7 @@ shared_ptrs - + @@ -2702,7 +2712,7 @@ shared_ptrs - + @@ -2711,7 +2721,7 @@ shared_ptrs - + @@ -2720,7 +2730,7 @@ shared_ptrs - + @@ -2729,7 +2739,7 @@ shared_ptrs - + @@ -2738,7 +2748,7 @@ shared_ptrs - + @@ -2747,7 +2757,7 @@ shared_ptrs - + @@ -2756,7 +2766,7 @@ shared_ptrs - + @@ -2765,7 +2775,7 @@ shared_ptrs - + @@ -2774,7 +2784,7 @@ shared_ptrs - + @@ -2783,7 +2793,7 @@ shared_ptrs - + @@ -2792,7 +2802,7 @@ shared_ptrs - + @@ -2801,7 +2811,7 @@ shared_ptrs - + @@ -2810,16 +2820,16 @@ shared_ptrs - + - + - + @@ -2828,7 +2838,7 @@ shared_ptrs - + @@ -2837,27 +2847,27 @@ shared_ptrs - + - - - + - + - + + + - + @@ -2866,7 +2876,7 @@ shared_ptrs - + @@ -2875,7 +2885,7 @@ shared_ptrs - + @@ -2884,18 +2894,18 @@ shared_ptrs - + - + - + @@ -2904,7 +2914,7 @@ shared_ptrs - + @@ -2913,87 +2923,109 @@ shared_ptrs - + + owns + + + + + + + - + + owns + + + + + + + - + - + - + + - + - - - + - + - - - - + + - + + - + - - - - + + - + + - + - + + + + + + + + + + + - + + - + - - - + - + @@ -3002,41 +3034,25 @@ shared_ptrs - + - owns - - - - - - - - + - owns - - - - - - - - + @@ -3046,16 +3062,18 @@ shared_ptrs - + - + - + + - + + @@ -3065,7 +3083,8 @@ shared_ptrs - + + @@ -3075,7 +3094,8 @@ shared_ptrs - + + @@ -3085,7 +3105,19 @@ shared_ptrs - + + + + + + + + + + + + + @@ -3095,7 +3127,8 @@ shared_ptrs - + + @@ -3105,7 +3138,8 @@ shared_ptrs - + + @@ -3115,7 +3149,8 @@ shared_ptrs - + + @@ -3125,7 +3160,8 @@ shared_ptrs - + + @@ -3135,75 +3171,133 @@ shared_ptrs - + + + no + + + + + + + - + + - - - + + yes + + + + + + + - + + - + - + + - + + - + - + + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + + - + + - + - + + - + + + yes + + + + + + + - + + @@ -3213,6 +3307,66 @@ shared_ptrs + + + + + + + + no + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 34a7eaf..992c537 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,7 +74,6 @@ set(SOURCES host/pingerfactory.cpp host/pinginterval.cpp host/pingprotocol.cpp - host/pingrotate.cpp host/pingscheduler.cpp tools/pcap.cpp icmp/icmpdata.cpp diff --git a/src/dns/dnscache.cpp b/src/dns/dnscache.cpp index e87c039..d516ae2 100644 --- a/src/dns/dnscache.cpp +++ b/src/dns/dnscache.cpp @@ -48,6 +48,16 @@ namespace Config int MaxRetrievalRecursions = 10; } +Cname::Cname() + : Host() + , Ttl() +{} + +Cname::Cname(const std::string &host, const uint32_t ttl) + : Host( host ) + , Ttl( ttl ) +{} + DnsCache::DnsCache(const IoServiceItem &io_serv, const std::string &cache_file) : IpCache() @@ -186,7 +196,7 @@ void DnsCache::update(const std::string &hostname, const Cname &cname) { GlobalLogger.info() << "DnsCache: update CNAME for " << hostname - << " to " << cname.first; + << " to " << cname.Host; CnameCache[hostname] = cname; HasChanged = true; } @@ -213,6 +223,9 @@ void DnsCache::update(const std::string &hostname, } +/** + * @returns empty list if no (up to date) ips for hostname in cache + */ HostAddressVec DnsCache::get_ips(const std::string &hostname, const bool check_up_to_date) { @@ -220,8 +233,8 @@ HostAddressVec DnsCache::get_ips(const std::string &hostname, if (check_up_to_date) { HostAddressVec result_up_to_date; - int threshold = DnsMaster::get_instance() - ->get_resolved_ip_ttl_threshold(); + uint32_t threshold = static_cast( + DnsMaster::get_instance()->get_resolved_ip_ttl_threshold() ); BOOST_FOREACH( const HostAddress &addr, result ) { if (addr.get_ttl().get_updated_value() > threshold) @@ -237,25 +250,31 @@ HostAddressVec DnsCache::get_ips(const std::string &hostname, return result; } -std::string DnsCache::get_cname(const std::string &hostname, - const bool check_up_to_date) +/** + * @returns empty cname if no (up to date cname) for hostname in cache + */ +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.first << "\""; - if (check_up_to_date) + << " --> \"" << result_obj.Host << "\""; + if (result_obj.Host.empty()) + return result_obj; + + else if (check_up_to_date) { - if (result_obj.second.get_updated_value() > DnsMaster::get_instance() + if (result_obj.Ttl.get_updated_value() > DnsMaster::get_instance() ->get_resolved_ip_ttl_threshold()) - return result_obj.first; + return result_obj; else { - GlobalLogger.debug() << "DnsCache: Cname is out of date"; - return ""; + GlobalLogger.debug() << "DnsCache: CNAME is out of date"; + return Cname(); // same as if there was no cname for hostname } } else - return result_obj.first; + return result_obj; } // underlying assumption in this function: for a hostname, the cache has either @@ -264,11 +283,14 @@ HostAddressVec DnsCache::get_ips_recursive(const std::string &hostname, const bool check_up_to_date) { std::string current_host = hostname; + Cname current_cname; HostAddressVec result = get_ips(current_host); int n_recursions = 0; + uint32_t min_cname_ttl = 0xffff; // largest possible unsigned 4-byte value while ( result.empty() ) { - current_host = get_cname(current_host, check_up_to_date); + current_cname = get_cname(current_host, check_up_to_date); + current_host = current_cname.Host; if (current_host.empty()) break; else if (++n_recursions >= Config::MaxRetrievalRecursions) @@ -278,10 +300,71 @@ HostAddressVec DnsCache::get_ips_recursive(const std::string &hostname, break; } else + { + min_cname_ttl = min(min_cname_ttl, current_cname.Ttl.get_value()); result = get_ips(current_host, check_up_to_date); + } + } + + GlobalLogger.debug() << "DnsCache: recursive IP retrieval resulted in " + << result.size() << "-list after " << n_recursions + << " recursions"; + + // adjust ttl to min of ttl and min_cname_ttl + if (n_recursions > 0) + { + TimeToLive cname_ttl(min_cname_ttl); + + BOOST_FOREACH( HostAddress &addr, result ) + { + if (addr.get_ttl().get_value() > min_cname_ttl) + addr.set_ttl(cname_ttl); + } } + return result; } +/** + * from a list of CNAMEs find the first one that is out of date + * + * required in ResolverBase::get_skipper + * + * Assume you have the following situation in cache with TTLs below: + * hostname --> cname1 --> cname2 --> ... --> cnameN [--> IP] + * 100 0 --> return cname2 + * 100 100 100 100 --> return cnameN + * ( with N < Config::MaxRetrievalRecursions ) + * hostname --> IP (no cnames involved) --> return hostname + */ +std::string DnsCache::get_first_outdated_cname(const std::string &hostname, + const uint32_t ttl_thresh) +{ + std::string up_to_date_host = hostname; + Cname cname; + int n_recursions = 0; + while (true) + { + if (++n_recursions >= Config::MaxRetrievalRecursions) + { + GlobalLogger.warning() << "DnsCache: reached recursion limit of " + << n_recursions << " in search of outdated CNAMEs!"; + break; + } + + cname = get_cname(up_to_date_host); + if (cname.Host.empty()) + // reached end of cname list + break; + else if (cname.Ttl.get_updated_value() > ttl_thresh) + // cname is up to date --> continue looking + up_to_date_host = cname.Host; + else + // cname is out of date --> return that + break; + } + return up_to_date_host; +} + // (created using vim -- the world's best text editor) diff --git a/src/dns/dnscache.h b/src/dns/dnscache.h index c213777..7a0fbe8 100644 --- a/src/dns/dnscache.h +++ b/src/dns/dnscache.h @@ -28,6 +28,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "host/pinger.h" // for IoserviceItem #include "dns/hostaddress.h" @@ -35,10 +41,42 @@ typedef std::vector HostAddressVec; typedef std::map ip_map_type; -typedef std::pair Cname; + +// ----------------------------------------------------------------------------- +// CNAME +// ----------------------------------------------------------------------------- + +struct Cname +{ // all public: + std::string Host; + TimeToLive Ttl; + + Cname(); + Cname(const std::string &host, const uint32_t ttl); + + // serialization + friend class boost::serialization::access; + template + void save(Archive & ar, const unsigned int version) const + { + ar & BOOST_SERIALIZATION_NVP(Host); + ar & BOOST_SERIALIZATION_NVP(Ttl); + } + template + void load(Archive & ar, const unsigned int version) + { + ar & BOOST_SERIALIZATION_NVP(Host); + ar & BOOST_SERIALIZATION_NVP(Ttl); + } + BOOST_SERIALIZATION_SPLIT_MEMBER() +}; typedef std::map cname_map_type; +// ----------------------------------------------------------------------------- +// DnsCache +// ----------------------------------------------------------------------------- + class DnsCache { public: @@ -50,12 +88,16 @@ public: void update(const std::string &hostname, const HostAddressVec &new_data); void update(const std::string &hostname, const Cname &cname); void update(const std::string &hostname, const uint32_t ttl); + + // retrieval 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); + const bool check_up_to_date=false); + Cname 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); + const bool check_up_to_date=false); + std::string get_first_outdated_cname(const std::string &hostname, + const uint32_t ttl_thresh); // variables private: @@ -65,7 +107,7 @@ private: std::string CacheFile; bool HasChanged; -// functions +// internal functions private: void schedule_save(const boost::system::error_code &error); void save_to_cachefile(); diff --git a/src/dns/dnsresolver.cpp b/src/dns/dnsresolver.cpp index 139219c..1e236d3 100644 --- a/src/dns/dnsresolver.cpp +++ b/src/dns/dnsresolver.cpp @@ -72,7 +72,6 @@ DnsResolver::DnsResolver(IoServiceItem &io_serv, , LogPrefix( "DnsResolver" ) , RandomIdGenerator() , RequestId( 0 ) - , Recursor() , OperationCancelled( false ) { std::stringstream temp; @@ -129,7 +128,7 @@ void DnsResolver::do_resolve() // create DNS request boost::net::dns::message dns_message( ResolverBase::Hostname, Protocol ); - dns_message.recursive(false); + dns_message.recursive(true); dns_message.action(boost::net::dns::message::query); dns_message.opcode(boost::net::dns::message::squery); @@ -236,8 +235,8 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, // remember cname list (if there were any) 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; + GlobalLogger.info() << LogPrefix << "Remember CNAME " + << host_and_cname.first << " --> " << host_and_cname.second.Host; ResolverBase::update_cache(host_and_cname.first, host_and_cname.second); } @@ -248,67 +247,25 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, // re-start resolving with that handle_cname(result_cnames); else - { // 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_name_servers); - GlobalLogger.debug() << "Checking ADDITIONALS section of dns reply"; - gather_results(result_message.additionals(), &result_ips, - &result_cnames, &result_name_servers); - - // search for a name_server for which an IP is given - bool have_recursed = false; - 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 (name_server.second == host_and_addr.first) - { - GlobalLogger.info() << LogPrefix << "Ask next name_server " - << name_server.second << " with IP " - << host_and_addr.second.get_ip() << " (responsible for " - << name_server.first << ")"; - have_recursed = true; - handle_recurse( host_and_addr.second ); - break; - } - } - if (have_recursed) - break; - } - - if ( !have_recursed ) - { // 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!"; - handle_unavailable(); - } - else - { - GlobalLogger.warning() << LogPrefix - << "There are " << result_name_servers.size() - << " name_servers given but none with IP!"; - handle_recurse_without_ip(result_name_servers[0].second); - } - } + { // no answers --> cannot proceed + GlobalLogger.warning() << LogPrefix << "No IP nor CNAME received! " + << "--> schedule retry"; + schedule_retry(); } } -void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers, +/** + * gather IPs, CNAMEs and name servers from list of resource records; + * + * can be run on anwers(), autorities() and additional() sections of dns reply + * messages + * + * @param rr_list: input list of resource records + * @param result_ips: output vector of ips + * @param result_cnames: output vector of cnames + * @param result_name_servers: output vector of name servers + */ +void DnsResolver::gather_results(const boost::net::dns::rr_list_t *rr_list, std::vector *result_ips, std::vector *result_cnames, std::vector *result_name_servers) @@ -316,7 +273,7 @@ void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers, { using boost::net::dns::resource_base_t; boost::posix_time::ptime now =boost::posix_time::second_clock::local_time(); - BOOST_FOREACH( boost::shared_ptr rr_item, *answers ) + BOOST_FOREACH( boost::shared_ptr rr_item, *rr_list ) { boost::net::dns::type_t rr_type = rr_item->rtype(); uint32_t ttl = rr_item->ttl(); @@ -453,7 +410,6 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) // We assume here that this list might not be in order but that all cnames // 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 src_cname_pair &host_and_cname, result_cnames ) @@ -461,7 +417,7 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) could_be_last = true; BOOST_REVERSE_FOREACH( const src_cname_pair &other, result_cnames ) { - if (other.first == host_and_cname.second.first) + if (other.first == host_and_cname.second.Host) { // found cname for current cname could_be_last = false; break; @@ -469,7 +425,7 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) } if (could_be_last) { - last_cname = host_and_cname.second.first; + last_cname = host_and_cname.second.Host; break; } } @@ -482,7 +438,7 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) GlobalLogger.info() << LogPrefix << "Result CNAMEs were:"; BOOST_FOREACH( const src_cname_pair &host_and_cname, result_cnames ) GlobalLogger.info() << LogPrefix << host_and_cname.first << " --> " - << host_and_cname.second.first; + << host_and_cname.second.Host; handle_unavailable(); } else @@ -493,14 +449,11 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) if ( !cached_data.empty() ) { bool was_success = true; - int recursion_count = 1; // define cache access as only 1 - finalize_resolve(was_success, recursion_count); + int cname_count = 1; // define cache access as only 1 + finalize_resolve(was_success, cname_count); } else { // get resolver for canonical name - // as opposed to the interal Recursor variable used in - // handle_recurse, this is a "proper" resolver that is maintained - // and cached by DnsMaster --> independent of this Resolver ResolverItem resolver = DnsMaster::get_instance() ->get_resolver_for(last_cname, Protocol); callback_type callback = boost::bind( @@ -518,7 +471,7 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) void DnsResolver::cname_resolve_callback(const bool was_success, - const int recursion_count) + const int cname_count) { if ( OperationCancelled ) { // async_resolve was cancelled --> callbacks already called @@ -531,153 +484,16 @@ void DnsResolver::cname_resolve_callback(const bool was_success, else GlobalLogger.info() << LogPrefix << "CNAME resolution failed"; // no use to schedule retry in this case since cname resolver must have - // failed several times and we can just re-start the same procedure with - // the same information (in recursion can try different name server) - // --> no schedule_retry + // failed several times and we can only re-start the same procedure with + // the same information // cname counts like one more recursion step ... - finalize_resolve(was_success, recursion_count+1); -} - - -void DnsResolver::handle_recurse(const HostAddress &name_server) -{ - // get resolver for same hostname but using a different name server - 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_recursor_for( - Hostname, Protocol, name_server.get_ip()); - callback_type callback = boost::bind( - &DnsResolver::recursive_resolve_callback, - this, name_server.get_ttl().get_value(), - _1, _2 ); - Recursor->async_resolve( callback ); - - // do not cancel timers or reset RetryCount - //stop_trying(); -} - - -void DnsResolver::recursive_resolve_callback(const uint32_t min_ttl, - const bool was_success, - const int recursion_count) -{ - GlobalLogger.debug() - << "Recursion back at request with name server " << NameServer; - - // do not need recursor any more; next time re-create from different random - // name server; may have been reset already in cancel_resolve(), so that - // is ok. If not, issue a warning - if ( !Recursor ) - { - if ( !OperationCancelled ) - GlobalLogger.warning() << LogPrefix - << "Recursor was reset before callback!"; - } - else - Recursor.reset(); - - if ( OperationCancelled ) - { // async_resolve was cancelled --> callbacks already called - GlobalLogger.info() << LogPrefix - << "Ignoring recursion results since we were cancelled"; - return; - } - else if (was_success) - { - // make sure the saved TTL is not larger than the one we found here - ResolverBase::update_cache(min_ttl); - finalize_resolve(was_success, recursion_count+1); - } - else - { - GlobalLogger.info() << LogPrefix << "Recursive resolution failed"; - schedule_retry(); - } -} - - -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(); - } + finalize_resolve(was_success, cname_count+1); } void DnsResolver::finalize_resolve(const bool was_success, - const int recursion_count) + const int cname_count) { // some consistency checks; failure might indicate a situation I had not // anticipated during programming but might not be harmfull yet @@ -698,12 +514,12 @@ void DnsResolver::finalize_resolve(const bool was_success, stop_trying(); // schedule callbacks, clearing callback list - ResolverBase::schedule_callbacks(was_success, recursion_count); + ResolverBase::schedule_callbacks(was_success, cname_count); // finalize GlobalLogger.notice() << LogPrefix << "finalized resolve" << " with success = " << was_success - << " and recursion_count = " << recursion_count; + << " and cname_count = " << cname_count; IsResolving = false; } @@ -749,17 +565,14 @@ void DnsResolver::cancel_resolve() return; } - if ( Recursor ) - 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 // OperationCancelled is true RequestId = 0; bool was_success = false; - int recursion_count = 1; - finalize_resolve(was_success, recursion_count); + int cname_count = 1; + finalize_resolve(was_success, cname_count); // set after finalize_resolve, so can check in finalize_resolve that // OperationCancelled is never true @@ -799,13 +612,7 @@ void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error) void DnsResolver::schedule_retry() { - // this function is called in all sorts of error cases - // --> need to clean up a bit - if ( Recursor ) - { - Recursor->cancel_resolve(); - Recursor.reset(); - } + // cancel timers ResolveTimeoutTimer.cancel(); PauseBeforeRetryTimer.cancel(); diff --git a/src/dns/dnsresolver.h b/src/dns/dnsresolver.h index a705f50..1e8ce1a 100644 --- a/src/dns/dnsresolver.h +++ b/src/dns/dnsresolver.h @@ -83,20 +83,13 @@ private: void handle_unavailable(); void handle_ips(const std::vector &result_ips); void handle_cname(const std::vector &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); + const int cname_count); void schedule_retry(); - void finalize_resolve(const bool success, const int recursion_count=0); + 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); - void gather_results( const boost::net::dns::rr_list_t *answers, + void gather_results( const boost::net::dns::rr_list_t *rr_list, std::vector *result_ips, std::vector *result_cnames, std::vector *result_nameservers ) const; @@ -113,11 +106,11 @@ private: boost::asio::deadline_timer StaleDataLongtermTimer; std::size_t NextIpIndex; int RetryCount; - bool IsResolving; + bool IsResolving; // true from async_resolve until finalize_resolve; + // false e.g. while waiting for StaleDataLongtermTimer std::string LogPrefix; boost::uuids::random_generator RandomIdGenerator; uint16_t RequestId; - ResolverItem Recursor; bool OperationCancelled; }; diff --git a/src/dns/resolverbase.cpp b/src/dns/resolverbase.cpp index d28b6eb..1ca1375 100644 --- a/src/dns/resolverbase.cpp +++ b/src/dns/resolverbase.cpp @@ -55,6 +55,21 @@ ResolverBase::ResolverBase(const IoServiceItem &io_serv, std::string ResolverBase::get_hostname() const { return Hostname; } +std::string ResolverBase::get_skipper() const +{ + DnsMasterItem master = DnsMaster::get_instance(); + std::string first_out_of_date = Cache->get_first_outdated_cname( + Hostname, + master->get_resolved_ip_ttl_threshold() ); + if ( first_out_of_date == Hostname ) + return ""; + else + // we want to skip this first outdated cname, so return what is + // directly behind it. + // If that is not a cname but ips, will return empty here + return Cache->get_cname(first_out_of_date).Host; +} + void ResolverBase::update_cache( const std::string &hostname, const HostAddressVec &new_results ) const { Cache->update( hostname, new_results ); } diff --git a/src/dns/resolverbase.h b/src/dns/resolverbase.h index c731b66..3b0fa09 100644 --- a/src/dns/resolverbase.h +++ b/src/dns/resolverbase.h @@ -34,6 +34,10 @@ typedef boost::function callback_type; typedef std::queue callback_list_type; +class ResolverBase; +typedef boost::shared_ptr ResolverItem; + + /** * @brief: abstract base class for DnsResolver and IpPseudoResolver */ @@ -57,6 +61,8 @@ public: std::string get_hostname() const; + std::string get_skipper() const; + protected: ResolverBase(const IoServiceItem &io_serv, const std::string &hostname, @@ -90,8 +96,6 @@ protected: }; -typedef boost::shared_ptr ResolverItem; - #endif // (created using vim -- the world's best text editor) diff --git a/src/dns/timetolive.h b/src/dns/timetolive.h index f1162dd..70d9433 100644 --- a/src/dns/timetolive.h +++ b/src/dns/timetolive.h @@ -26,6 +26,7 @@ on this file might be covered by the GNU General Public License. #include #include #include +#include #include // forward declaration @@ -47,14 +48,6 @@ public: uint32_t get_updated_value() const; private: - // required for saving and loading TtlSetTime to original value - friend class HostAddress; - //template - //friend void HostAddress::load(Archive & ar, const unsigned int version); - //template - //friend void HostAddress::save(Archive & ar, const unsigned int version) - // const; - /// the numeric time-to-live uint32_t Ttl; /// the time when the time-to-live was set, so it is possible to know the diff --git a/src/host/pinger.h b/src/host/pinger.h index 72a4839..47d3e21 100644 --- a/src/host/pinger.h +++ b/src/host/pinger.h @@ -29,6 +29,7 @@ #include #include #include +#include #include //----------------------------------------------------------------------------- @@ -54,7 +55,7 @@ public: typedef boost::weak_ptr WeakPtr; virtual void ping( - const std::string &destination_ip, + const boost::asio::ip::address &ip, const uint16_t destination_port, boost::function ping_done_callback ) = 0; diff --git a/src/host/pingerfactory.cpp b/src/host/pingerfactory.cpp index 085ef6f..a919b9a 100644 --- a/src/host/pingerfactory.cpp +++ b/src/host/pingerfactory.cpp @@ -124,40 +124,3 @@ PingerItem PingerFactory::createPinger( return PingerItem(); //lint !e527 } -/** - * @brief Create a Pinger object suitable to the given list of protocols. - * - * @param protocol_list A list of the available ping protocols. - * @param io_serv The @c io_service object. - * @param network_interface The network interface name from where the ping - * packet will be sent. - * @param destination_address The remote address to ping. - * @param destination_port The remote port to ping. - * - * @return a Pinger object to able to ping using the given list of protocols. - */ -PingRotateItem PingerFactory::createPinger( - const PingProtocolList &protocol_list, - const IoServiceItem io_serv, - const string &network_interface, - const string &destination_address, - const uint16_t destination_port, - const int resolved_ip_ttl_threshold, - const int ping_reply_timeout -) -{ - BOOST_ASSERT( 0 < protocol_list.size() ); - BOOST_ASSERT( !network_interface.empty() ); - BOOST_ASSERT( !destination_address.empty() ); - BOOST_ASSERT( 0 < destination_port ); - - return PingRotateItem( new PingRotate( - io_serv, - network_interface, - destination_address, - destination_port, - resolved_ip_ttl_threshold, - ping_reply_timeout, - protocol_list - ) ); -} diff --git a/src/host/pingerfactory.h b/src/host/pingerfactory.h index b735ecf..0d03e6c 100644 --- a/src/host/pingerfactory.h +++ b/src/host/pingerfactory.h @@ -28,7 +28,6 @@ #include "host/pinger.h" #include "host/pingprotocol.h" -#include "host/pingrotate.h" //----------------------------------------------------------------------------- // PingerFactory @@ -44,16 +43,6 @@ public: const int ping_reply_timeout ); - static PingRotateItem createPinger( - const PingProtocolList &protocol_list, - const IoServiceItem io_serv, - const std::string &network_interface, - const std::string &destination_address, - const uint16_t destination_port, - const int resolved_ip_ttl_threshold, - const int ping_reply_timeout - ); - private: PingerFactory(); ~PingerFactory(); diff --git a/src/host/pingscheduler.cpp b/src/host/pingscheduler.cpp index ed82e8a..2b476f4 100644 --- a/src/host/pingscheduler.cpp +++ b/src/host/pingscheduler.cpp @@ -72,32 +72,35 @@ PingScheduler::PingScheduler( const int first_delay ) : + IoService( io_serv ), + NetworkInterfaceName( network_interface ), + Resolver(), + DestinationAddress( destination_address ), + DestinationPort( destination_port ), NextPingTimer( *io_serv ), - NextAddressTimer( *io_serv ), TimeSentLastPing( microsec_clock::universal_time() ), PingIntervalInSec( ping_interval_in_sec ), - AddressResolveIntervalInSec( ping_interval_in_sec ), HostAnalyzer( destination_address, ping_fail_percentage_limit, link_analyzer ), FirstDelay( first_delay ), - AddressResolutionAttempts( 0 ), - EverHadAnyIP( false ), Ping() { BOOST_ASSERT( !network_interface.empty() ); BOOST_ASSERT( !destination_address.empty() ); - BOOST_ASSERT( 0 < destination_port ); + BOOST_ASSERT( ( 0 < destination_port ) && + ( destination_port < numeric_limits::max() ) ); BOOST_ASSERT( 0 < ping_interval_in_sec ); - BOOST_ASSERT( (0 <= ping_fail_percentage_limit) && (ping_fail_percentage_limit <= 100) ); - - Ping = PingerFactory::createPinger( - ping_protocol_list, - io_serv, - network_interface, - destination_address, - destination_port, - resolved_ip_ttl_threshold, - ping_reply_timeout - ); + BOOST_ASSERT( (0 <= ping_fail_percentage_limit) && + ( ping_fail_percentage_limit <= 100) ); + + std::stringstream temp; + temp << "PS(" << DestinationAddress << "): "; + LogPrefix = temp.str(); + + // fill circular buffer with protocols + BOOST_FOREACH( const PingProtocol &prot, protocol_list ) + ProtocolRotate.push_back(prot); + + init_ping_protocol(); } /** @@ -112,6 +115,7 @@ void PingScheduler::stop_pinging() // stop pinger, which will probably call ping_done_handler --> re-new NextPingTimer GlobalLogger.debug() << "scheduler: stop pinging" << endl; Ping->stop_pinging(); + Resolver->cancel_resolve(); // now cancel the own timer GlobalLogger.debug() << "scheduler: cancel timer" << endl; @@ -119,93 +123,82 @@ void PingScheduler::stop_pinging() } /** - * @brief Start into infinite loop of calls to resolve_and_ping + * @brief Start into infinite loop of calls to ping * * Does not start yet but set NextPingTimer (possibly to 0), so action starts * when io_service is started */ void PingScheduler::start_pinging() { - // assume that even at re-start there is no IP known - EverHadAnyIP = false; - if ( FirstDelay > 0 ) GlobalLogger.info() << "Delaying first ping by " << FirstDelay << "s"; else GlobalLogger.info() << "Schedule ping as soon as possible"; (void) NextPingTimer.expires_from_now( seconds( FirstDelay ) ); - NextPingTimer.async_wait( bind( &PingScheduler::resolve_and_ping, this, + NextPingTimer.async_wait( bind( &PingScheduler::ping, this, boost::asio::placeholders::error ) ); } /** - * @brief Check whether need to resolve host names via DNS and then - * call ping; - * If name resolution fails too often, reports this to HostAnalyzer + * @brief call Ping::ping and schedule a call to ping_done_handler when finished */ -void PingScheduler::resolve_and_ping(const boost::system::error_code &error) +void PingScheduler::ping(const boost::system::error_code &error) { if ( error ) { // get here, e.g. by NextPingTimer.cancel in stop_pinging if ( error == boost::asio::error::operation_aborted ) - GlobalLogger.error() << "Timer for resolve_and_ping was cancelled! Stopping" << endl; + GlobalLogger.error() << "Timer for ping was cancelled! " + << "Stopping" << endl; else GlobalLogger.error() << "Received error " << error - << " waiting for resolve_and_ping! Stopping" << endl; + << " waiting for ping! Stopping" + << endl; return; } - bool ips_up_to_date = EverHadAnyIP && Ping->have_up_to_date_ip(); + // ping as soon as dns is ready + WantToPing = true; + try_to_ping(); +} + - // determine if address resolution is required - if ( !ips_up_to_date ) +void PingRotate::try_to_ping() +{ + if ( !WantToPing ) { - Ping->start_resolving_ping_address(); // try to resolve - if ( ips_up_to_date ) - { - EverHadAnyIP = true; - HostAnalyzer.set_resolved_ip_count( Ping->get_resolved_ip_count() ); - AddressResolutionAttempts = 0; - } + GlobalLogger.info() << "PingRotate: not pinging yet (not requested to)"; + return; } - // (may still have no or only outdated IPs) + else if ( Resolver && Resolver->is_resolving() ) + { + GlobalLogger.info() << "PingRotate: not pinging yet (DNS not finished)"; + return; + } + else if ( !Resolver ) + // should not happen, but check anyway + GlobalLogger.warning() << LogPrefix << "Have no resolver!"; + GlobalLogger.info() << "PingRotate: start ping"; + WantToPing = false; - if ( EverHadAnyIP ) - { // have IPs --> can ping (even if IPs are out of date) - if ( !ips_up_to_date ) - GlobalLogger.info() << "Using outdated IPs" << endl; - ping(); - } - else - { // no IPs --> try again later, possibly report offline before - AddressResolutionAttempts++; - if (AddressResolutionAttempts >= 10) //MaxAddressResolutionAttempts) - { - GlobalLogger.notice() << "No IPs after " << AddressResolutionAttempts << " DNS queries!"; - HostAnalyzer.report_dns_resolution_failure(); - } - (void) NextAddressTimer.expires_from_now( seconds( AddressResolveIntervalInSec ) ); - NextAddressTimer.async_wait( bind( &PingScheduler::resolve_and_ping, this, - boost::asio::placeholders::error ) ); - } + Ping->ping( + Resolver->get_next_ip().get_ip(), + DestinationPort, + boost::bind(&PingScheduler::ping_done_handler, this, _1) + ); } -/** - * @brief call Ping::ping and schedule a call to ping_done_handler when finished - */ -void PingScheduler::ping() -{ - Ping->ping( boost::bind(&PingScheduler::ping_done_handler, this, _1) ); -} +//------------------------------------------------------------------------------ +// Post Processing of Ping result +//------------------------------------------------------------------------------ /** * @brief called when Ping::ping is done; calls functions to update * statistics, ping interval and elapsed time; - * schedules a call to resolve_and_ping, thereby closing the loop + * schedules a call to ping, thereby closing the loop */ void PingScheduler::ping_done_handler( const bool ping_success ) { @@ -218,9 +211,12 @@ void PingScheduler::ping_done_handler( const bool ping_success ) update_ping_interval(); update_ping_elapsed_time(); + // get next protocol, possibly start resolving IPs + update_ping_protocol(); + // schedule next ping (void) NextPingTimer.expires_from_now( seconds( PingIntervalInSec ) ); - NextPingTimer.async_wait( bind( &PingScheduler::resolve_and_ping, this, + NextPingTimer.async_wait( bind( &PingScheduler::ping, this, boost::asio::placeholders::error ) ); } @@ -253,3 +249,114 @@ void PingScheduler::update_ping_elapsed_time() TimeSentLastPing = microsec_clock::universal_time(); } + +//------------------------------------------------------------------------------ +// Ping Protocol Rotation +//------------------------------------------------------------------------------ + +void PingRotate::init_ping_protocol() +{ + get_next_ping_protocol(); +} + +void PingRotate::update_ping_protocol() +{ + if ( can_change_ping_protocol() ) + { + get_next_ping_protocol(); + } +} + +void PingRotate::get_next_ping_protocol() +{ + PingProtocol ping_protocol = ProtocolRotate.front(); + ProtocolRotate.pop_front(); + ProtocolRotate.push_back(ping_protocol); + + if (Ping) + Ping->stop_pinging(); + + Ping = PingerFactory::createPinger(ping_protocol, IoService, + NetworkInterfaceName, PingReplyTimeout); + + update_dns_resolver( ping_protocol ); +} + +bool PingRotate::can_change_ping_protocol() const +{ + // TODO can_change_ping_protocol() and get_next_ping_protocol() may be implemented in a Algorithm + // class that can be exchanged in this class to provide an algorithm neutral class + return true; +} + +//------------------------------------------------------------------------------ +// DNS host name resolution +//------------------------------------------------------------------------------ +// +void PingRotate::update_dns_resolver( PingProtocol current_protocol ) +{ + if (Resolver && Resolver->is_resolving()) + { + GlobalLogger.warning() << "Resolver still seems to be resolving " + << "--> cancel!"; + Resolver->cancel_resolve(); + } + + // DNS master caches created resolvers and resolved IPs, so this will + // probably just return an existing resolver with already resolved IPs for + // requested protocol ( ICMP/TCP is ignored, only IPv4/v6 is important) + Resolver = DnsMaster::get_instance()->get_resolver_for(DestinationAddress, + current_protocol); + // start resolving if no ips available + if ( Resolver->have_up_to_date_ip() ) + { + if (!Resolver->is_resolving()) + GlobalLogger.warning() << "PingRotate: have up to date IPs but " + << "resolver seems to be resolving all the same... " + << "Start pinging anyway!"; + try_to_ping(); + } + else + start_resolving_ping_address(); +} + +void PingRotate::start_resolving_ping_address() //lint !e1762 +{ + Resolver->async_resolve( boost::bind(&PingRotate::dns_resolve_callback, + this, _1, _2) ); +} + +void PingRotate::dns_resolve_callback(const bool was_success, + const int cname_count) +{ + GlobalLogger.info() << "PingRotate: dns resolution finished " + << "with success = " << was_success << " " + << "and cname_count = " << cname_count; + + if ( !was_success ) + { // host name resolution failed; try again bypassing first CNAME(s) + std::string skip_host = Resolver->get_skipper(); + + if (skip_host.empty()) + { + GlobalLogger.notice() << LogPrefix << "DNS failed, " + << "try anyway with cached data"; + HostAnalyzer->set_resolved_ip_count(0); + try_to_ping(); + } + else + { + GlobalLogger.notice() << LogPrefix << "DNS failed, " + << "try again skipping a CNAME and resolving " + << skip_host << " directly"; + Resolver = DnsMaster::get_instance() + ->get_resolver_for(skip_host, PingRotate.back()); + start_resolving_ping_address(); + } + } + else + { + HostAnalyzer->set_resolved_ip_count( Resolver->get_resolved_ip_count()); + try_to_ping(); + } +} diff --git a/src/host/pingscheduler.h b/src/host/pingscheduler.h index 75598b9..250bf85 100644 --- a/src/host/pingscheduler.h +++ b/src/host/pingscheduler.h @@ -77,6 +77,16 @@ private: void update_ping_interval(); void update_ping_elapsed_time(); + void init_ping_protocol(); + void update_ping_protocol(); + void get_next_ping_protocol(); + bool can_change_ping_protocol() const; + + void update_dns_resolver( PingProtocol current_protocol ); + + void try_to_ping(); + void dns_resolve_callback(const bool was_success, const int cname_count); + // // Attributes // @@ -94,14 +104,27 @@ private: /// Object responsible to evaluate the status of the host HostStatus HostAnalyzer; /// delay for very first ping to avoid lots of simultaneous pings - int FirstDelay; - /// number of attempts at Address Resolution - int AddressResolutionAttempts; - /// flag whether any DNS lookup succeeded - // (comparing get_ip_count to 0 might violate assertion in dnsresolver.cpp) - bool EverHadAnyIP; + int FirstDelay; + /// The IO service object, which has the loop event + IoServiceItem IoService; + /// The network interface name + std::string NetworkInterfaceName; + /// The Dns resolver + ResolverItem Resolver; + /// The address to ping + std::string DestinationAddress; + /// The port to ping at destination host (same port to all protocols in the list) + uint16_t DestinationPort; + /// time threshold for address resolution + int ResolvedIpTtlThreshold; + /// timeout for ping reply + const int PingReplyTimeout; + /// The list of protocols to ping + CircularProtocolList ProtocolRotate; /// Internal boost pinger object - PingRotateItem Ping; + PingerItem Ping; + /// a flag whether we should ping as soon as dns is ready + bool WantToPing; }; //----------------------------------------------------------------------------- diff --git a/src/icmp/icmppinger.cpp b/src/icmp/icmppinger.cpp index 8296252..501a8b7 100644 --- a/src/icmp/icmppinger.cpp +++ b/src/icmp/icmppinger.cpp @@ -122,7 +122,7 @@ IcmpPinger::~IcmpPinger() * @return void. */ void IcmpPinger::ping( - const string &destination_ip, + const address &destination_ip, const uint16_t /*destination_port*/, // the ICMP protocol does not use ports function ping_done_callback ) @@ -167,13 +167,10 @@ void IcmpPinger::stop_pinging() } -void IcmpPinger::set_destination_endpoint( const string &destination_ip ) +void IcmpPinger::set_destination_endpoint( const address &destination_ip ) { - BOOST_ASSERT( !destination_ip.empty() ); - uint16_t port = 0; - address destination_address = address::from_string( destination_ip ); - DestinationEndpoint = icmp::endpoint( destination_address, port ); + DestinationEndpoint = icmp::endpoint( destination_ip, port ); } bool IcmpPinger::start_send() diff --git a/src/icmp/icmppinger.h b/src/icmp/icmppinger.h index d3463c4..c1e1e6a 100644 --- a/src/icmp/icmppinger.h +++ b/src/icmp/icmppinger.h @@ -125,7 +125,7 @@ public: virtual ~IcmpPinger(); virtual void ping( - const std::string &destination_ip, + const boost::asio::ip::address &destination_ip, const uint16_t destination_port, boost::function ping_done_callback ); @@ -144,7 +144,7 @@ private: const IcmpPacketDistributorItem distributor ); - void set_destination_endpoint( const std::string &destination_ip ); + void set_destination_endpoint(const boost::asio::ip::address &destination); bool start_send(); bool send_echo_request( const IcmpPacketItem icmp_packet ); diff --git a/src/tcp/tcppinger.cpp b/src/tcp/tcppinger.cpp index 79347f6..1cd857d 100644 --- a/src/tcp/tcppinger.cpp +++ b/src/tcp/tcppinger.cpp @@ -113,12 +113,11 @@ TcpPinger::~TcpPinger() * @return void. */ void TcpPinger::ping( - const string &destination_ip, + const address &destination_ip, const uint16_t destination_port, function ping_done_callback ) { - BOOST_ASSERT( !destination_ip.empty() ); BOOST_ASSERT( ( 0 < destination_port ) && ( destination_port < numeric_limits::max() ) ); PingDoneCallback = ping_done_callback; @@ -159,17 +158,15 @@ uint16_t TcpPinger::get_destination_port() const } void TcpPinger::set_destination_endpoint( - const string &destination_ip, + const address &destination_ip, const uint16_t destination_port ) { - BOOST_ASSERT( !destination_ip.empty() ); BOOST_ASSERT( ( 0 < destination_port ) && ( destination_port < numeric_limits::max() ) ); BOOST_ASSERT( sizeof(uint16_t) <= sizeof(destination_port) ); - address destination_address = address::from_string( destination_ip ); uint16_t port = static_cast( destination_port ); - DestinationEndpoint = tcp_raw_protocol::endpoint( destination_address, port ); + DestinationEndpoint = tcp_raw_protocol::endpoint( destination_ip, port ); } void TcpPinger::start_send() diff --git a/src/tcp/tcppinger.h b/src/tcp/tcppinger.h index 8a6329f..19effee 100644 --- a/src/tcp/tcppinger.h +++ b/src/tcp/tcppinger.h @@ -47,7 +47,7 @@ public: virtual ~TcpPinger(); virtual void ping( - const std::string &destination_ip, + const boost::asio::ip::address &destination_ip, const uint16_t destination_port, boost::function ping_done_callback ); @@ -76,7 +76,7 @@ private: uint16_t get_destination_port() const; void set_destination_endpoint( - const std::string &destination_ip, + const boost::asio::ip::address &destination_ip, const uint16_t destination_port );