From: Guilherme Maciel Ferreira Date: Fri, 18 Mar 2011 11:39:53 +0000 (+0100) Subject: Handle the error when a host cannot be resolved X-Git-Tag: v1.0~133 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=09de3c4b673ed59c0b13eb67ef4dea03f385bfff;p=pingcheck Handle the error when a host cannot be resolved - reorganization of PingScheduler to do not ping a host that was not resolved - from now, the DnsResolver::resolve() method must be explicitly called by the client of the class --- diff --git a/Readme b/Readme index 0733905..e4cfe76 100644 --- a/Readme +++ b/Readme @@ -88,6 +88,23 @@ where: they are optional and not required in public release. +2.4. Error Handling +--------------------------------------- +There are two basic kinds of errors that shall happen in the program, errors +that the program can recover (expected) and errors that the progam can not or +should not recover from (exceptional errors). Bellow the description and the +method adopted to deal with each one: +- Expected: these errors can occur and must be handled by boolean return values. + (i.e. if a host is down, if the address was not resolved). This errors can + happen, but THE PROGRAM MUST CONTINUE TO OPERATE EVEN IF THEY HAPPEN. +- Exceptional: these are the kinds of errors that should not occur. They must be + handled by exceptions and THE PROGRAM MUST HALT IF THEY HAPPEN. +Thus, to keep things as simple as possible, this program adopts just two kinds +of error detection and handling: +- Return Boolean Value for expected errors and +- Handle Exceptions for exceptional errors. + + 3. Source Code ======================================= diff --git a/src/dns/dnsresolver.cpp b/src/dns/dnsresolver.cpp index 54cb70a..eaf8370 100644 --- a/src/dns/dnsresolver.cpp +++ b/src/dns/dnsresolver.cpp @@ -14,16 +14,62 @@ using namespace boost::asio::ip; // DnsResolver //----------------------------------------------------------------------------- -DnsResolver::DnsResolver( string dns_address ) : - ResolvedHostAddressList() +DnsResolver::DnsResolver( const string &dns_address ) : + ResolvedHostAddressList(), + HostDnsAddress( dns_address ) { - resolve( dns_address ); } DnsResolver::~DnsResolver() { } +/** + * Resolve the IPs from this DNS and build a list of these IPs. + * + * @return true if the host address could be resolved, or false otherwise. + */ +bool DnsResolver::resolve() +{ + BOOST_ASSERT( !HostDnsAddress.empty() ); + + cerr << "* Host : " << HostDnsAddress << endl; + + try + { + io_service io_service; + tcp::resolver resolver( io_service ); + tcp::resolver::query query( tcp::v4(), HostDnsAddress, "" ); + tcp::resolver::iterator it_first = resolver.resolve( query ); + tcp::resolver::iterator it_last = tcp::resolver::iterator(); + while ( it_first != it_last ) + { + string ip = (*it_first).endpoint().address().to_string(); + + HostAddress resolved_host; + resolved_host.set_ip( ip ); + ResolvedHostAddressList.push_back( resolved_host ); + + cerr << ip << endl; + + ++it_first; + } + } + catch ( boost::system::system_error& ex ) + { + cerr << "Error: host " << HostDnsAddress << " could not be resolved." + << endl; + return false; + } + + BOOST_ASSERT( 1 <= ResolvedHostAddressList.size() ); + + return true; +} + +/** + * @return the amount of IPs resolved for the DNS. + */ int DnsResolver::get_resolved_ip_count() { int resolved_ip_count = ResolvedHostAddressList.size(); @@ -33,6 +79,10 @@ int DnsResolver::get_resolved_ip_count() return resolved_ip_count; } +/** + * @return the next IP string in the list of resolved IPs. When reach the last + * IP, it goes back to first, like a circular buffer. + */ string DnsResolver::get_next_ip() { uint list_size_before = ResolvedHostAddressList.size(); @@ -43,40 +93,8 @@ string DnsResolver::get_next_ip() ResolvedHostAddressList.push_back( host_address ); uint list_size_after = ResolvedHostAddressList.size(); + BOOST_ASSERT( list_size_before == list_size_after ); return destination_ip; } - -/** - * Resolve which IPs belong to the given DNS and build a list of these IPs. - * - * @param dns_address The DNS address to be query for IPs. - */ -void DnsResolver::resolve( string dns_address ) -{ - BOOST_ASSERT( !dns_address.empty() ); - - cerr << " - Host : " << dns_address << endl; - - io_service io_service; - tcp::resolver resolver( io_service ); - tcp::resolver::query query( tcp::v4(), dns_address, "" ); - // TODO can throw exceptions if a host is not found - tcp::resolver::iterator it_first = resolver.resolve( query ); - tcp::resolver::iterator it_last = tcp::resolver::iterator(); - while ( it_first != it_last ) - { - string ip = (*it_first).endpoint().address().to_string(); - - HostAddress resolved_host; - resolved_host.set_ip( ip ); - ResolvedHostAddressList.push_back( resolved_host ); - - cerr << " |_ " << ip << endl; - - ++it_first; - } - - BOOST_ASSERT( 0 < ResolvedHostAddressList.size() ); -} diff --git a/src/dns/dnsresolver.h b/src/dns/dnsresolver.h index 635b5ab..990cf31 100644 --- a/src/dns/dnsresolver.h +++ b/src/dns/dnsresolver.h @@ -13,17 +13,16 @@ class HostAddress; class DnsResolver { public: - explicit DnsResolver( std::string dns_address ); + explicit DnsResolver( const std::string &dns_address ); virtual ~DnsResolver(); + bool resolve(); int get_resolved_ip_count(); std::string get_next_ip(); private: - void resolve( std::string dns_address ); - -private: std::list ResolvedHostAddressList; + const std::string HostDnsAddress; }; diff --git a/src/ping/pingscheduler.cpp b/src/ping/pingscheduler.cpp index d0956d8..ee320e7 100644 --- a/src/ping/pingscheduler.cpp +++ b/src/ping/pingscheduler.cpp @@ -28,22 +28,47 @@ PingScheduler::PingScheduler( PingIntervalInSec( ping_interval_in_sec ), Analyzer( ping_address, 50 ) // 50% max acceptable failure { - uint resolved_ip_count = IpList.get_resolved_ip_count(); - Analyzer.set_resolved_ip_count( resolved_ip_count ); } PingScheduler::~PingScheduler() { } -void PingScheduler::start_pinging() +bool PingScheduler::start_pinging() { - string destination_ip = IpList.get_next_ip(); + bool address_resolved = resolve_ping_address(); + if ( !address_resolved ) + { + return false; + } + + schedule_next_ping(); + + return true; +} + +bool PingScheduler::resolve_ping_address() +{ + bool address_resolved = IpList.resolve(); + if ( !address_resolved ) + { + return false; + } + + int resolved_ip_count = IpList.get_resolved_ip_count(); + Analyzer.set_resolved_ip_count( resolved_ip_count ); + return true; +} + +void PingScheduler::setup_ping() +{ + BOOST_ASSERT( 1 <= IpList.get_resolved_ip_count() ); + + string destination_ip = IpList.get_next_ip(); bool ping_success = ping( destination_ip ); update_ping_statistics( ping_success ); - update_ping_elapsed_time(); schedule_next_ping(); @@ -60,6 +85,19 @@ bool PingScheduler::ping( const string &destination ) return pinger.ping( destination ); } +void PingScheduler::schedule_next_ping() +{ + BOOST_ASSERT( 0 < PingIntervalInSec ); + + Timer.expires_from_now( seconds( PingIntervalInSec ) ); + Timer.async_wait( bind( &PingScheduler::handle_next_ping, this ) ); +} + +void PingScheduler::handle_next_ping() +{ + setup_ping(); +} + void PingScheduler::update_ping_statistics( const bool ping_success ) { Analyzer.update_ping_statistics( ping_success ); @@ -73,14 +111,3 @@ void PingScheduler::update_ping_elapsed_time() TimeSentLastPing = microsec_clock::universal_time(); } - -void PingScheduler::schedule_next_ping() -{ - Timer.expires_from_now( seconds( PingIntervalInSec ) ); - Timer.async_wait( bind( &PingScheduler::handle_next_ping, this ) ); -} - -void PingScheduler::handle_next_ping() -{ - start_pinging(); -} diff --git a/src/ping/pingscheduler.h b/src/ping/pingscheduler.h index e33b977..f4bc992 100644 --- a/src/ping/pingscheduler.h +++ b/src/ping/pingscheduler.h @@ -23,14 +23,16 @@ public: ); virtual ~PingScheduler(); - void start_pinging(); + bool start_pinging(); private: + bool resolve_ping_address(); + void setup_ping(); bool ping( const std::string &destination ); - void update_ping_statistics( const bool ping_success ); - void update_ping_elapsed_time(); void schedule_next_ping(); void handle_next_ping(); + void update_ping_statistics( const bool ping_success ); + void update_ping_elapsed_time(); private: boost::asio::io_service &IoService;