--- /dev/null
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+
+ Christian Herdtweck, Intra2net AG 2015
+ */
+
+#ifndef DNS_CNAME_H
+#define DNS_CNAME_H
+
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/serialization/split_member.hpp>
+#include <boost/serialization/string.hpp>
+
+#include "dns/timetolive.h"
+
+// -----------------------------------------------------------------------------
+// CNAME
+// -----------------------------------------------------------------------------
+
+struct Cname
+{ // all public:
+ std::string Host;
+ TimeToLive Ttl;
+
+ Cname();
+ Cname(const std::string &host, const uint32_t ttl);
+ Cname(const std::string &host, const TimeToLive &ttl);
+
+ // serialization
+ friend class boost::serialization::access;
+ template<class Archive>
+ void save(Archive & ar, const unsigned int version) const
+ {
+ ar & BOOST_SERIALIZATION_NVP(Host);
+ ar & BOOST_SERIALIZATION_NVP(Ttl);
+ }
+ template<class Archive>
+ void load(Archive & ar, const unsigned int version)
+ {
+ ar & BOOST_SERIALIZATION_NVP(Host);
+ ar & BOOST_SERIALIZATION_NVP(Ttl);
+ }
+ BOOST_SERIALIZATION_SPLIT_MEMBER()
+};
+
+#endif
using boost::posix_time::seconds;
using I2n::Logger::GlobalLogger;
+
namespace Config
{
int SaveTimerSeconds = 60;
, Ttl( ttl )
{}
+
+const string DnsCache::DoNotUseCacheFile = "do not use cache file!";
+
DnsCache::DnsCache(const IoServiceItem &io_serv,
const std::string &cache_file)
: IpCache()
else if (CacheFile.empty())
GlobalLogger.warning()
<< "DnsCache: skip saving because file name empty!";
- else if (CacheFile == DO_NOT_USE_CACHE_FILE)
+ else if (CacheFile == DoNotUseCacheFile)
GlobalLogger.info() << "DnsCache: configured not to use cache file";
else
{
//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;
+ GlobalLogger.info() << "DnsCache: saved to cache file "
+ << CacheFile;
HasChanged = false;
}
{
if (CacheFile.empty())
GlobalLogger.warning()
- << "DnsCache: cannot load because cache file name is empty!";
- else if (CacheFile == DO_NOT_USE_CACHE_FILE)
+ << "DnsCache: cannot load because cache file name is empty!";
+ else if (CacheFile == DoNotUseCacheFile)
GlobalLogger.info() << "DnsCache: configured not to use cache file";
else if ( !I2n::file_exists(CacheFile) )
GlobalLogger.warning() << "DnsCache: cannot load because cache file "
}
catch (boost::archive::archive_exception &exc)
{
- GlobalLogger.warning() << "DnsCache: archive exception loading from "
- << CacheFile << ": " << exc.what();
+ GlobalLogger.warning()
+ << "DnsCache: archive exception loading from " << CacheFile
+ << ": " << exc.what();
}
catch (std::exception &exc)
{
while ( result.empty() )
{
current_cname = get_cname(current_host, check_up_to_date);
- current_host = key_for_hostname(current_cname.Host);
- if (current_host.empty())
+ if (current_cname.Host.empty())
break;
- else if (++n_recursions >= Config::MaxRetrievalRecursions)
+
+ current_host = key_for_hostname(current_cname.Host);
+ if (++n_recursions >= Config::MaxRetrievalRecursions)
{
GlobalLogger.warning() << "DnsCache: reached recursion limit of "
<< n_recursions << " in recursive IP retrieval!";
BOOST_FOREACH( HostAddress &addr, result )
{
if (addr.get_ttl().get_value() > min_cname_ttl)
+ {
+ GlobalLogger.debug() << "DnsCache: using shorter CNAME TTL";
addr.set_ttl(cname_ttl);
+ }
}
}
std::string DnsCache::get_first_outdated_cname(const std::string &hostname,
const uint32_t ttl_thresh)
{
- std::string up_to_date_host = hostname;
+ std::string first_outdated = hostname;
Cname cname;
int n_recursions = 0;
while (true)
break;
}
- cname = get_cname(up_to_date_host);
- if (key_for_hostname(cname.Host).empty())
+ cname = get_cname(first_outdated);
+ 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;
+ first_outdated = cname.Host;
else
- // cname is out of date --> return that
+ { // cname is out of date --> return its target
+ first_outdated = cname.Host;
break;
+ }
}
- return up_to_date_host;
+ return first_outdated;
}
// (created using vim -- the world's best text editor)
#include <boost/system/error_code.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
-#include <boost/serialization/access.hpp>
-#include <boost/serialization/nvp.hpp>
-#include <boost/serialization/split_member.hpp>
-#include <boost/serialization/string.hpp>
#include "host/pinger.h" // for IoserviceItem
#include "dns/hostaddress.h"
-#include "dns/timetolive.h"
+#include "dns/cname.h"
typedef std::vector<HostAddress> HostAddressVec;
typedef std::map<std::string, HostAddressVec> ip_map_type;
-
-// -----------------------------------------------------------------------------
-// CNAME
-// -----------------------------------------------------------------------------
-
-struct Cname
-{ // all public:
- std::string Host;
- TimeToLive Ttl;
-
- Cname();
- Cname(const std::string &host, const uint32_t ttl);
- Cname(const std::string &host, const TimeToLive &ttl);
-
- // serialization
- friend class boost::serialization::access;
- template<class Archive>
- void save(Archive & ar, const unsigned int version) const
- {
- ar & BOOST_SERIALIZATION_NVP(Host);
- ar & BOOST_SERIALIZATION_NVP(Ttl);
- }
- template<class Archive>
- 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<std::string, Cname> cname_map_type;
-/// constant to give as cache_file arg to DnsCache constructor
-/// indicating that no cache file should be used
-const std::string DO_NOT_USE_CACHE_FILE = "do not use cache file!";
-
-
// -----------------------------------------------------------------------------
// DnsCache
// -----------------------------------------------------------------------------
class DnsCache
{
public:
+ /// constant to give as cache_file arg to DnsCache constructor
+ /// indicating that no cache file should be used
+ static const std::string DoNotUseCacheFile;
+
DnsCache( const IoServiceItem &io_serv,
const std::string &cache_file );
~DnsCache();
DnsMasterItem DnsMaster::TheOnlyInstance;
+// just delegates work to other create_master function
void DnsMaster::create_master(const IoServiceItem &io_serv,
const boost::asio::ip::address &default_name_server,
const int resolved_ip_ttl_threshold,
const int max_address_resolution_attempts,
const std::string &cache_file)
{
+ GlobalLogger.info() << "Creating DNS 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);
+}
+
+void DnsMaster::create_master(const IoServiceItem &io_serv,
+ const boost::asio::ip::address &default_name_server,
+ const int resolved_ip_ttl_threshold,
+ const int max_address_resolution_attempts,
+ const DnsCacheItem &cache)
+{
if (TheOnlyInstance)
{
GlobalLogger.warning()
return;
}
- GlobalLogger.info() << "Creating DNS Cache and Master";
- DnsCacheItem cache( new DnsCache(io_serv, cache_file) );
+ GlobalLogger.info() << "Creating DNS Master";
TheOnlyInstance.reset( new DnsMaster(io_serv,
default_name_server,
resolved_ip_ttl_threshold,
);
}
-
DnsMaster::DnsMaster(const IoServiceItem &io_serv,
const boost::asio::ip::address &default_name_server,
const int resolved_ip_ttl_threshold,
const int resolved_ip_ttl_threshold,
const int max_address_resolution_attempts,
const std::string &cache_file);
+ static void create_master(const IoServiceItem &io_serv,
+ const boost::asio::ip::address &default_name_server,
+ const int resolved_ip_ttl_threshold,
+ const int max_address_resolution_attempts,
+ const DnsCacheItem &cache); // needed for unit test
static DnsMasterItem& get_instance();
~DnsMaster();
{
if ( error == boost::asio::error::operation_aborted ) // cancelled
{
- GlobalLogger.warning() << LogPrefix
- << "Resolve timeout timer was cancelled!";
+ GlobalLogger.info() << LogPrefix
+ << "Resolve timeout timer was cancelled!";
return;
}
else if (error)
if ( error == boost::asio::error::operation_aborted ) // cancelled
{ // assume that our code cancelled this timer, so callbacks will be
// taken care of!
- GlobalLogger.warning() << LogPrefix
- << "Resolve wait timer was cancelled! ";
+ GlobalLogger.info() << LogPrefix
+ << "Resolve wait timer was cancelled! ";
}
else if (error)
{ // not sure what to do here, but callers waiting forever for a callback
int DnsResolver::get_resolved_ip_count()
{
+ // run with empty hostname (--> uses internal var Hostname)
+ // and check_up_to_date = true
return ResolverBase::get_cached_ips_recursively("", true).size();
}
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;
+ return first_out_of_date;
}
void ResolverBase::update_cache( const std::string &hostname,
Ping(),
WantToPing( false ),
LogPrefix(),
- ContinueOnOutdatedIps( false );
+ ContinueOnOutdatedIps( false )
{
BOOST_ASSERT( !network_interface.empty() );
BOOST_ASSERT( !destination_address.empty() );
// ping as soon as dns is ready
WantToPing = true;
- try_to_ping();
+ ping_when_ready();
}
-void PingScheduler::try_to_ping()
+void PingScheduler::ping_when_ready()
{
if ( !WantToPing )
{
GlobalLogger.info() << "PingScheduler: start ping";
WantToPing = false;
+ // try to get an up-to-date IP
HostAddress ip = Resolver->get_next_ip();
+
if ( !ip.is_valid() && ContinueOnOutdatedIps)
- {
+ { // we failed to resolve --> try to use outdated IP
GlobalLogger.info() << LogPrefix << "Checking for outdated IPs";
bool check_up_to_date = false;
ip = Resolver->get_next_ip(check_up_to_date);
GlobalLogger.error() << LogPrefix << "No IP to ping "
<< "-- this should not have happened!!";
WantToPing = true;
- if ( !Resolver.is_resolving() )
+ if ( !Resolver->is_resolving() )
start_resolving_ping_address();
}
+
+ // next time try with up-to-date IP
+ ContinueOnOutdatedIps = false;
}
//------------------------------------------------------------------------------
// show "!" after host name if running on outdated IPs
-void update_log_prefix()
+void PingScheduler::update_log_prefix()
{
std::stringstream temp;
temp << "PS(" << DestinationAddress;
GlobalLogger.warning() << "PingScheduler: have up to date IPs but "
<< "resolver seems to be resolving all the same... "
<< "Start pinging anyway!";
- try_to_ping();
+ ping_when_ready();
}
else
start_resolving_ping_address();
// TODO this is too simple, but need to think more about how to update here!
// (may have to switch back some time to resolver for original host or so
- ContinueOnOutdatedIps = true;
+ ContinueOnOutdatedIps = !was_success;
update_log_prefix();
if ( was_success )
{
HostAnalyzer.set_resolved_ip_count( Resolver->get_resolved_ip_count());
- try_to_ping();
+ ping_when_ready();
}
else
{ // host name resolution failed; try again bypassing first outdated CNAME
+ // or using cached IP
std::string skip_host = Resolver->get_skip_cname();
if (skip_host.empty())
- {
+ { // continue with IP
GlobalLogger.notice() << LogPrefix << "DNS failed, "
<< "try anyway with cached data";
HostAnalyzer.set_resolved_ip_count(0);
- try_to_ping();
+ ping_when_ready();
}
else
- {
+ { // have CNAME to continue
GlobalLogger.notice() << LogPrefix << "DNS failed, "
<< "try again skipping a CNAME and resolving "
<< skip_host << " directly";
Resolver = DnsMaster::get_instance()
->get_resolver_for(skip_host, *ProtocolIter);
- // the original resolver is still alive and cached by DnsMaster
- // and counting down the time to re-try on its own
start_resolving_ping_address();
+
+ // (the original resolver is still alive and cached by DnsMaster and
+ // counting down time to re-try on its own until cancel_resolve)
}
}
}
void update_dns_resolver( PingProtocol current_protocol );
- void try_to_ping();
+ void ping_when_ready();
void dns_resolve_callback(const bool was_success, const int cname_count);
void start_resolving_ping_address();
#include <boost/test/unit_test.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/address.hpp>
+#include <boost/bind.hpp>
+
+#include <logfunc.hpp>
#include "host/pingprotocol.h"
#include "dns/hostaddress.h"
#include "dns/dnsmaster.h"
#include "dns/dnscache.h"
#include "dns/resolverbase.h"
+#include "dns/cname.h"
+
+using boost::asio::ip::address;
//------------------------------------------------------------------------------
-// helper functions
+// Global Test fixture (created once for test suite)
//------------------------------------------------------------------------------
-void create_master();
+// constants for master
+address name_server = address::from_string("127.0.0.1");
+int resolved_ip_ttl_threshold = 3;
+int max_address_resolution_attempts = 2;
+std::string cache_file = DnsCache::DoNotUseCacheFile;
+
+// rely on boost that there will only be one instance
+struct GlobalFixture;
+GlobalFixture *global_fixture;
-// TODO: try to run this only once for test suite
-void create_master()
+
+struct GlobalFixture
{
- // only create if it does not exist yet
- DnsMasterItem master = DnsMaster::get_instance();
- if ( !master )
+
+ GlobalFixture()
+ : IoService()
+ , Cache()
+ , Master()
{
- boost::asio::ip::address name_server =
- boost::asio::ip::address::from_string("127.0.0.1");
- int resolved_ip_ttl_threshold = 3;
- int max_address_resolution_attempts = 2;
- std::string cache_file = DO_NOT_USE_CACHE_FILE;
- IoServiceItem io_serv;
-
- // create it
- DnsMaster::create_master(io_serv,
+ BOOST_TEST_MESSAGE("Create global fixture");
+
+ // setup logging so we can see output from out code
+ I2n::Logger::enable_stderr_log( true );
+ I2n::Logger::set_log_level( I2n::Logger::LogLevel::Debug );
+ I2n::Logger::GlobalLogger.info() << "Logging enabled for DnsTest";
+
+ // IoService
+ IoServiceItem io_service_temp( new boost::asio::io_service() );
+ io_service_temp.swap( IoService );
+ io_service_temp.reset();
+
+ // DNS Cache
+ DnsCacheItem cache_temp = DnsCacheItem(
+ new DnsCache(IoService, cache_file) );
+ cache_temp.swap( Cache );
+ cache_temp.reset();
+ fill_cache();
+
+ // create master
+ DnsMaster::create_master(IoService,
name_server,
resolved_ip_ttl_threshold,
max_address_resolution_attempts,
- cache_file);
- master = DnsMaster::get_instance();
-
- // simple checks
- BOOST_CHECK_EQUAL( master->get_resolved_ip_ttl_threshold(),
- resolved_ip_ttl_threshold );
- BOOST_CHECK_EQUAL( master->get_max_address_resolution_attempts(),
- max_address_resolution_attempts );
+ Cache);
+ Master = DnsMaster::get_instance();
+
+ // remember this instance, so we can later access all these variables
+ if (global_fixture == 0)
+ global_fixture = this;
}
-}
+
+ ~GlobalFixture()
+ {
+ BOOST_TEST_MESSAGE("Destructing global fixture");
+ IoService->stop();
+ IoService.reset();
+ Master.reset();
+ }
+
+ void fill_cache()
+ {
+ BOOST_TEST_MESSAGE( "Filling cache..." );
+ {
+ HostAddress ip(address::from_string("192.168.42.1"), 61);
+ HostAddressVec ips;
+ ips.push_back(ip);
+ Cache->update("host1.test", ips);
+ }
+
+ {
+ HostAddress ip1(address::from_string("192.168.42.2"), 92);
+ HostAddress ip2(address::from_string("192.168.42.3"), 93);
+ HostAddressVec ips;
+ ips.push_back(ip1);
+ ips.push_back(ip2);
+ Cache->update("host2_3.test", ips);
+ }
+
+ { // cname.test --> host1.test
+ Cname cname("host1.test", 35);
+ Cache->update("cname.test", cname);
+ }
+
+ { // cname2.test --> cname.test --> host1.test
+ Cname cname("cname.test", 33);
+ Cache->update("cname2.test", cname);
+ }
+
+ { // cname3.test --> cname2.test --> cname.test --> host1.test
+ Cname cname("cname2.test", 37);
+ Cache->update("cname3.test", cname);
+ }
+ BOOST_TEST_MESSAGE( "Done filling cache." );
+ }
+
+ // these variables will not be available in test cases:
+ IoServiceItem IoService;
+ DnsCacheItem Cache;
+ DnsMasterItem Master;
+};
+
+// this causes above fixture to be created only once before tests start and
+// destructed after tests end; however, variables are not accessible in test
+// cases
+BOOST_GLOBAL_FIXTURE( GlobalFixture )
+
+
+// using this as suite-level fixture makes variable Master accessible in all
+// test cases
+struct TestFixture
+{
+ IoServiceItem IoService;
+ DnsCacheItem Cache;
+ DnsMasterItem Master;
+
+ TestFixture()
+ : IoService()
+ , Cache()
+ , Master()
+ {
+ BOOST_TEST_MESSAGE("Create test-level fixture");
+ GlobalFixture *global = global_fixture;
+ IoService = global->IoService;
+ Cache = global->Cache;
+ Master = global->Master;
+ }
+
+ virtual ~TestFixture() {}
+};
//------------------------------------------------------------------------------
// test suite
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_SUITE( TestDns )
+BOOST_FIXTURE_TEST_SUITE( TestDns, TestFixture )
BOOST_AUTO_TEST_CASE( create_master )
{
- create_master();
+ // simple checks
+ BOOST_CHECK_EQUAL( Master->get_resolved_ip_ttl_threshold(),
+ resolved_ip_ttl_threshold );
+ BOOST_CHECK_EQUAL( Master->get_max_address_resolution_attempts(),
+ max_address_resolution_attempts );
}
-BOOST_AUTO_TEST_CASE( create_v4 )
+//------------------------------------------------------------------------------
+// test Cache
+//------------------------------------------------------------------------------
+BOOST_FIXTURE_TEST_SUITE( TestDnsCache, TestFixture )
+
+BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
{
- create_master();
+ HostAddressVec ips = Cache->get_ips("host1.test");
+ BOOST_CHECK_EQUAL( ips.size(), 1 );
+ HostAddress ip = ips.front();
+ BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
+ BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 61 );
+}
+
+
+BOOST_AUTO_TEST_CASE( cache_retrieve_ip2 )
+{
+ HostAddressVec ips = Cache->get_ips("host2_3.test");
+ BOOST_CHECK_EQUAL( ips.size(), 2 );
+ HostAddress ip = ips[0];
+ BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.2" );
+ BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 92 );
+ ip = ips[1];
+ BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.3" );
+ BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 93 );
+}
+BOOST_AUTO_TEST_CASE( cache_retrieve_cname )
+{
+ HostAddressVec ips = Cache->get_ips("cname.test");
+ BOOST_CHECK( ips.empty() );
+
+ Cname cname = Cache->get_cname("cname.test");
+ BOOST_CHECK_EQUAL( cname.Host, "host1.test" );
+ BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 35 );
+}
+
+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 );
+ HostAddress ip = ips.front();
+ BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
+ BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 35 );
+}
+
+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 );
+ HostAddress ip = ips.front();
+ BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.1" );
+ BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 33 );
+}
+
+BOOST_AUTO_TEST_CASE( cache_skip_test1 )
+{
+ // build a cname chain where first one is out of date
+ { // skip_chain_first -(120)-> skip_chain_second -(0)-> skip_chain_third
+ // -(120)-> skip_chain_fourth -(60)-> IPs
+ Cname first("skip_chain_second.test", 120);
+ Cache->update("skip_chain_first.test", first);
+ Cname second("skip_chain_third.test", 0);
+ Cache->update("skip_chain_second.test", second);
+ Cname third("skip_chain_fourth.test", 120);
+ Cache->update("skip_chain_third.test", third);
+ HostAddressVec ips;
+ ips.push_back( HostAddress( address::from_string("192.168.42.4"), 60) );
+ Cache->update("skip_chain_fourth.test", ips);
+ }
+
+ // normal recursive call should give nothing since all are outdated
+ bool check_up_to_date = true;
+ HostAddressVec ips = Cache->get_ips_recursive("skip_chain_first.test",
+ check_up_to_date);
+ BOOST_CHECK( ips.empty() );
+
+ // now try to skip
+ std::string first_outdated = Cache->get_first_outdated_cname(
+ "skip_chain_first.test", 5);
+ BOOST_CHECK_EQUAL( first_outdated, "skip_chain_third.test" );
+}
+
+
+BOOST_AUTO_TEST_SUITE_END() // of TestDnsCache
+
+
+// -----------------------------------------------------------------------------
+// test resolver
+// -----------------------------------------------------------------------------
+
+BOOST_FIXTURE_TEST_SUITE( TestDnsResolver, TestFixture )
+
+void resolve_callback(IoServiceItem io_serv, ResolverItem resolver,
+ const bool was_success, const int cname_count);
+
+BOOST_AUTO_TEST_CASE( create_resolver_v4 )
+{
// create resolver
std::string hostname = "www.intra2net.com";
- ResolverItem resolver = DnsMaster::get_instance()
- ->get_resolver_for(hostname, PingProtocol_ICMP);
+ ResolverItem resolver = Master->get_resolver_for(hostname,
+ PingProtocol_ICMP);
BOOST_CHECK_EQUAL( resolver->get_hostname(), hostname );
BOOST_CHECK( !resolver->is_resolving() );
BOOST_CHECK_EQUAL( resolver->get_next_ip().get_ip().to_string(), no_ip );
}
+
+void resolve_callback(IoServiceItem io_serv, ResolverItem resolver,
+ const bool was_success, const int cname_count)
+{
+ resolver->cancel_resolve();
+ io_serv->stop();
+ BOOST_TEST_MESSAGE( "Stopped io_service" );
+}
+
+
+BOOST_AUTO_TEST_CASE( do_resolve )
+{
+ // create resolver
+ std::string hostname = "www.intra2net.com";
+ ResolverItem resolver = Master->get_resolver_for(hostname,
+ PingProtocol_ICMP);
+
+ // set callback
+ callback_type callback = boost::bind( resolve_callback, IoService, resolver,
+ _1, _2 );
+ // start resolving
+ resolver->async_resolve(callback);
+ IoService->run();
+ // this will block until io service is stopped in resolve_callback
+
+ // check for result
+ BOOST_CHECK( resolver->have_up_to_date_ip() );
+}
+
+BOOST_AUTO_TEST_SUITE_END() // of TestDnsResolver
+
BOOST_AUTO_TEST_SUITE_END()