Turn BoostPinger into true async operation
authorThomas Jarosch <thomas.jarosch@intra2net.com>
Wed, 4 May 2011 16:10:38 +0000 (18:10 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Wed, 4 May 2011 16:13:15 +0000 (18:13 +0200)
src/host/boostpinger.cpp
src/host/boostpinger.h
src/host/pingscheduler.cpp
src/host/pingscheduler.h

index 58fe87b..cc25af8 100644 (file)
@@ -19,6 +19,7 @@
 #include "icmp/icmppacket.h"
 #include "icmp/icmptype.h"
 #include "icmp/ipv4header.h"
+#include "boostpinger.h"
 
 using namespace std;
 using boost::asio::const_buffers_1;
@@ -36,10 +37,11 @@ using I2n::Logger::GlobalLogger;
 //-----------------------------------------------------------------------------
 
 BoostPinger::BoostPinger(
+        boost::asio::io_service &io_service,
         string source_network_interface,
         const int echo_reply_timeout_in_sec
 ) :
-    IoService(),
+    IoService(io_service),
     DestinationEndpoint(),
     Socket( IoService, icmp::v4() ),
     IcmpPacketReceiveTimer( IoService ),
@@ -49,7 +51,8 @@ BoostPinger::BoostPinger(
     ReplyBuffer(),
     RepliesCount( 0 ),
     EchoReplyTimeoutInSec( echo_reply_timeout_in_sec ),
-    PingerStatus( PingStatus_NotSent )
+    PingerStatus( PingStatus_NotSent ),
+    PingDoneCallback()
 {
     if ( !source_network_interface.empty() &&
          !select_source_network_interface( source_network_interface ) )
@@ -74,29 +77,21 @@ BoostPinger::~BoostPinger()
  * Ping a destination address from an available local source.
  *
  * @param destination_ip The address of the host to ping.
- *
- * @return true if the ping was successfully performed, or false if the ping
- * was not replied due a timeout.
- *
- * @note This method is synchronous, i.e. this method blocks and returns only
- * after the ping requested has finished or timed-out.
+ * @param done_handler Done handler will be called on successful ping or timeout
  */
-bool BoostPinger::ping( const string &destination_ip )
+void BoostPinger::ping( const string &destination_ip, boost::function< void(bool) > ping_done_callback )
 {
     BOOST_ASSERT( !destination_ip.empty() );
 
+    PingDoneCallback = ping_done_callback;
+
     // Prepare ping
-    IoService.reset();
     PingerStatus = PingStatus_NotSent;
 
     set_destination_endpoint( destination_ip );
 
-    // if start_pinger() does not block, the PingerStatus will be equal to
-    // PingStatus_NotSent, thus ping_success will be false
-    start_pinger();
-
-    bool ping_success = (PingerStatus == PingStatus_SuccessReply);
-    return ping_success;
+    start_send();
+    start_receive();
 }
 
 void BoostPinger::set_destination_endpoint( const string &destination_ip )
@@ -108,33 +103,14 @@ void BoostPinger::set_destination_endpoint( const string &destination_ip )
     DestinationEndpoint = icmp::endpoint( destination_address, port );
 }
 
-void BoostPinger::start_pinger()
-{
-    start_send();
-    start_receive();
-
-    (void) IoService.run();
-}
-
-void BoostPinger::stop_pinger()
-{
-    IoService.stop();
-}
-
 void BoostPinger::start_send()
 {
     ++SequenceNumber;
 
     IcmpPacket icmp_echo_request_packet = create_echo_request( SequenceNumber );
 
-    if ( PingerStatus == PingStatus_NotSent )
-    {
-        send_echo_request( icmp_echo_request_packet );
-    }
-    else
-    {
-        stop_pinger();
-    }
+    BOOST_ASSERT( PingerStatus == PingStatus_NotSent );
+    send_echo_request( icmp_echo_request_packet );
 }
 
 IcmpPacket BoostPinger::create_echo_request(
@@ -196,7 +172,7 @@ void BoostPinger::schedule_timeout_echo_reply()
             TimeSent + seconds( EchoReplyTimeoutInSec )
     );
     IcmpPacketReceiveTimer.async_wait(
-            boost::bind( &BoostPinger::handle_timeout_icmp_packet, this )
+            boost::bind( &BoostPinger::handle_ping_done, this )
     );
 }
 
@@ -212,7 +188,12 @@ void BoostPinger::start_receive()
     );
 }
 
-void BoostPinger::handle_timeout_icmp_packet()
+/**
+ * @brief Gets called when the ping is finished: Either on timeout or on ping reply
+ *
+ * @return void
+ **/
+void BoostPinger::handle_ping_done()
 {
     // Check reply count as the timer handler
     // is also called by Timer.cancel();
@@ -222,6 +203,10 @@ void BoostPinger::handle_timeout_icmp_packet()
 
         set_ping_status( PingStatus_FailureTimeout );
     }
+
+    // Call ping-done handler
+    bool ping_success = (PingerStatus == PingStatus_SuccessReply);
+    PingDoneCallback(ping_success);
 }
 
 void BoostPinger::handle_receive_icmp_packet( const size_t &bytes_transferred )
index b0f4d9a..6d337fe 100644 (file)
@@ -2,6 +2,7 @@
 #define BOOSTPINGER_H
 
 #include <boost/asio.hpp>
+#include <boost/function.hpp>
 
 class IcmpPacket;
 
@@ -17,12 +18,13 @@ class BoostPinger
 {
 public:
     BoostPinger(
+            boost::asio::io_service &io_service,
             std::string source_network_interface,
             const int echo_reply_timeout_in_sec
     );
     virtual ~BoostPinger();
 
-    bool ping( const std::string &destination_ip );
+    void ping( const std::string &destination_ip, boost::function< void(bool) > ping_done_callback);
 
 private:
     enum PingStatus
@@ -35,8 +37,6 @@ private:
 
 private:
     void set_destination_endpoint( const std::string &destination_ip );
-    void start_pinger();
-    void stop_pinger();
 
     void start_send();
     IcmpPacket create_echo_request( const uint16_t sequence_number ) const;
@@ -44,8 +44,8 @@ private:
     void schedule_timeout_echo_reply();
 
     void start_receive();
-    void handle_timeout_icmp_packet();
     void handle_receive_icmp_packet( const std::size_t &bytes_transferred );
+    void handle_ping_done();
 
     void print_echo_reply(
             const IcmpPacket &icmp_packet,
@@ -65,7 +65,7 @@ private:
 
 private:
     /// io service object, which has the loop event
-    boost::asio::io_service IoService;
+    boost::asio::io_service &IoService;
     /// the destination host
     boost::asio::ip::icmp::endpoint DestinationEndpoint;
     /// the socket object
@@ -88,6 +88,7 @@ private:
     /// the status of the pinger
     BoostPinger::PingStatus PingerStatus;
 
+    boost::function< void(bool) > PingDoneCallback;
 };
 
 #endif /* BOOSTPINGER_H */
index 3375cf8..91f6a7a 100644 (file)
@@ -41,7 +41,7 @@ PingScheduler::PingScheduler(
     PingIntervalInSec( ping_interval_in_sec ),
     IpList( destination_address, nameserver ),
     HostAnalyzer( destination_address, ping_fail_percentage_limit, link_analyzer ),
-    Pinger(LocalNetworkInterfaceName, 5),
+    Pinger(IoService, LocalNetworkInterfaceName, 5),
     Thread()
 {
 }
@@ -115,11 +115,11 @@ bool PingScheduler::resolve_ping_address()
     return true;
 }
 
-bool PingScheduler::ping( const string &destination_ip )
+void PingScheduler::ping( const string &destination_ip )
 {
     BOOST_ASSERT( !destination_ip.empty() );
 
-    return Pinger.ping( destination_ip );
+    Pinger.ping( destination_ip, boost::bind(&PingScheduler::ping_done_handler, this, _1) );
 }
 
 void PingScheduler::setup_next_ping()
@@ -139,8 +139,11 @@ void PingScheduler::setup_next_ping()
     }
 
     string destination_ip = IpList.get_next_ip();
-    bool ping_success = ping( destination_ip );
+    ping( destination_ip);
+}
 
+void PingScheduler::ping_done_handler(bool ping_success)
+{
     update_ping_statistics( ping_success );
     update_ping_elapsed_time();
 
index 77e3af4..cea64ce 100644 (file)
@@ -45,7 +45,9 @@ private:
     void stop_pinging();
 
     bool resolve_ping_address();
-    bool ping( const std::string &destination_ip );
+    void ping( const std::string &destination_ip);
+    void ping_done_handler(bool ping_success);
+
     void setup_next_ping();
     void schedule_next_ping();