new signal handling in main; removed all thread-related vars, use same IoServiceItem...
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Tue, 30 Dec 2014 17:14:06 +0000 (18:14 +0100)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Tue, 30 Dec 2014 17:14:06 +0000 (18:14 +0100)
14 files changed:
src/CMakeLists.txt
src/host/pingerfactory.cpp
src/host/pingerfactory.h
src/host/pingrotate.cpp
src/host/pingrotate.h
src/host/pingscheduler.cpp
src/host/pingscheduler.h
src/icmp/icmppinger.cpp
src/icmp/icmppinger.h
src/link/linkstatus.cpp
src/link/linkstatus.h
src/main.cpp
src/tcp/tcppinger.cpp
src/tcp/tcppinger.h

index d9f1253..a1d5cd6 100644 (file)
@@ -3,9 +3,9 @@ include(FindPkgConfig)
 
 # package: required boost libraries
 set(Boost_USE_STATIC_LIBS OFF)
-set(Boost_USE_MULTITHREADED ON)
+set(Boost_USE_MULTITHREADED OFF)
 set(Boost_USE_STATIC_RUNTIME OFF)
-find_package(Boost 1.44 COMPONENTS filesystem program_options system thread REQUIRED)
+find_package(Boost 1.44 COMPONENTS filesystem program_options system REQUIRED)
 include_directories(${Boost_INCLUDE_DIRS})
 link_directories(${Boost_LIBRARY_DIRS})
 
index 24f2bcd..7df5039 100644 (file)
@@ -33,7 +33,6 @@
 
 using namespace std;
 using boost::shared_ptr;
-using boost::asio::io_service;
 using boost::asio::ip::icmp;
 using boost::asio::ip::tcp_raw_protocol;
 using boost::system::system_error;
@@ -67,7 +66,7 @@ PingerFactory::~PingerFactory()
  */
 PingerItem PingerFactory::createPinger(
         const PingProtocol protocol,
-        io_service &io_serv,
+        const IoServiceItem io_serv,
         const string &network_interface,
         const int ping_reply_timeout
 )
@@ -126,7 +125,7 @@ PingerItem PingerFactory::createPinger(
  */
 PingRotateItem PingerFactory::createPinger(
         const PingProtocolList &protocol_list,
-        io_service &io_serv,
+        const IoServiceItem io_serv,
         const string &network_interface,
         const string &destination_address,
         const uint16_t destination_port,
index 5e6e918..118ec24 100644 (file)
@@ -39,14 +39,14 @@ class PingerFactory
 public:
     static PingerItem createPinger(
             const PingProtocol protocol,
-            boost::asio::io_service &io_serv,
+            const IoServiceItem io_serv,
             const std::string &network_interface,
             const int ping_reply_timeout
     );
 
     static PingRotateItem createPinger(
             const PingProtocolList &protocol_list,
-            boost::asio::io_service &io_serv,
+            const IoServiceItem io_serv,
             const std::string &network_interface,
             const std::string &destination_address,
             const uint16_t destination_port,
index 598fb5c..19e2a43 100644 (file)
@@ -27,7 +27,6 @@
 #include "host/pingerfactory.h"
 
 using namespace std;
-using boost::asio::io_service;
 using boost::function;
 using boost::shared_ptr;
 
@@ -48,7 +47,7 @@ using boost::shared_ptr;
  * host. The protocols will be used in the order they are in the list.
  */
 PingRotate::PingRotate(
-        IoServiceItem io_serv,
+        const IoServiceItem io_serv,
         const string &network_interface,
         const string &destination_address,
         const uint16_t destination_port,
index 078b91b..e287e16 100644 (file)
@@ -46,7 +46,7 @@ class PingRotate
 {
 public:
     PingRotate(
-            IoServiceItem io_serv,
+            const IoServiceItem io_serv,
             const std::string &network_interface,
             const std::string &destination_address,
             const uint16_t destination_port,
index ca07c15..e7b9e3e 100644 (file)
@@ -39,7 +39,6 @@ using boost::date_time::time_resolution_traits_adapted64_impl;
 using boost::posix_time::microsec_clock;
 using boost::posix_time::ptime;
 using boost::posix_time::seconds;
-using boost::thread;
 using boost::shared_ptr;
 using I2n::Logger::GlobalLogger;
 
@@ -58,10 +57,10 @@ using I2n::Logger::GlobalLogger;
  * @param ping_fail_percentage_limit Maximum amount of pings that can fail.
  * @param nameserver Server to resolve the addresses.
  * @param link_analyzer The object to monitor the link status.
- * @param first_delay Delay in seconds from start_pinging_thread to first ping attempt
+ * @param first_delay Delay in seconds from start_pinging to first ping attempt
  */
 PingScheduler::PingScheduler(
-        IoServiceItem io_service,
+        const IoServiceItem io_service,
         const string &network_interface,
         const string &destination_address,
         const uint16_t destination_port,
@@ -76,9 +75,8 @@ PingScheduler::PingScheduler(
         const int first_delay
 
 ) :
-    IoService( io_service ),
-    NextPingTimer( io_service ),
-    NextAddressTimer( io_service ),
+    NextPingTimer( *io_service ),
+    NextAddressTimer( *io_service ),
     TimeSentLastPing( microsec_clock::universal_time() ),
     PingIntervalInSec( ping_interval_in_sec ),
     AddressResolveIntervalInSec( ping_interval_in_sec ),
@@ -87,8 +85,7 @@ PingScheduler::PingScheduler(
     AddressResolutionAttempts( 0 ),
     MaxAddressResolutionAttempts( max_address_resolution_attempts ),
     EverHadAnyIP( false ),
-    Ping(),
-    Thread()
+    Ping()
 {
     BOOST_ASSERT( !network_interface.empty() );
     BOOST_ASSERT( !destination_address.empty() );
@@ -99,7 +96,7 @@ PingScheduler::PingScheduler(
 
     Ping = PingerFactory::createPinger(
             ping_protocol_list,
-            IoService,
+            io_service,
             network_interface,
             destination_address,
             destination_port,
@@ -116,44 +113,13 @@ PingScheduler::~PingScheduler()
 {
 }
 
-/**
- * @brief Starts the pinging thread and returns immediately.
- */
-bool PingScheduler::start_pinging_thread()
-{
-    Thread = thread( &PingScheduler::start_pinging, this );                                             //lint !e1793
-
-    return true;
-}
-
-/**
- * @brief Waits for the pinging thread to finish.
- */
-void PingScheduler::wait_pinging_thread()
-{
-    BOOST_ASSERT( Thread.joinable() );
-
-    Thread.join();
-}
-
-/**
- * @brief Stops pinging the host. Request the thread to finish, which makes the
- * any blocking wait (join) on this object to return.
- */
-void PingScheduler::stop_pinging_thread()
-{
-    stop_pinging();
-}
-
 void PingScheduler::stop_pinging()
 {
-    // This is thread safe
-    IoService.stop();
 }
 
 /**
- * @brief Start into infinite loop of calls to resolve_and_ping, using an
- *   IoService which is started here and can be stopped through stop_pinging[_thread]
+ * @brief Start into infinite loop of calls to resolve_and_ping
+ *   IoService which is started here and can be stopped through stop_pinging
  */
 void PingScheduler::start_pinging()
 {
@@ -167,10 +133,6 @@ void PingScheduler::start_pinging()
     }
     else
         resolve_and_ping();
-
-    // event processing loop, it is a blocking call!
-    IoService.run();                                                                                    //lint !e534
-    GlobalLogger.info() << "Ping thread was stopped.";
 }
 
 
index 8192a9e..1cdeaec 100644 (file)
@@ -27,7 +27,6 @@ on this file might be covered by the GNU General Public License.
 
 #include <boost/asio.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/thread.hpp>
 
 #include "link/linkstatus.h"
 #include "host/hoststatus.h"
@@ -49,6 +48,7 @@ class PingScheduler
 {
 public:
     PingScheduler(
+            const IoServiceItem io_service,
             const std::string &network_interface,
             const std::string &destination_address,
             const uint16_t destination_port,
@@ -64,18 +64,14 @@ public:
     );
     ~PingScheduler();
 
-    bool start_pinging_thread();
-    void wait_pinging_thread();
-    void stop_pinging_thread();
+    void start_pinging();
+    void stop_pinging();
 
 private:
     //
     // Methods
     //
 
-    void start_pinging();
-    void stop_pinging();
-
     void resolve_and_ping();
     bool resolve_address();
     void force_address_resolution();
@@ -89,8 +85,6 @@ private:
     // Attributes
     //
 
-    /// Service object, which has the event loop
-    boost::asio::io_service IoService;
     /// Timer to trigger the next ping
     boost::asio::deadline_timer NextPingTimer;
     /// Timer to trigger the next attempt to resolve addresses
@@ -113,8 +107,6 @@ private:
     bool EverHadAnyIP;
     /// Internal boost pinger object
     PingRotateItem Ping;
-    /// Thread object
-    boost::thread Thread;
 };
 
 //-----------------------------------------------------------------------------
index c1076a7..fa76a05 100644 (file)
@@ -51,17 +51,16 @@ static const std::size_t SOCKET_BUFFER_SIZE = 65536;   // 64kB
  * @param echo_reply_timeout_in_sec The amount of time to wait for a reply.
  */
 IcmpPinger::IcmpPinger(
-        io_service &io_serv,
+        const IoServiceItem io_serv,
         const icmp::socket::protocol_type &protocol,
         const string &source_network_interface,
         const int echo_reply_timeout_in_sec
 ) :
-    IoService( io_serv ),
     DestinationEndpoint(),
     Protocol( protocol ),
-    Socket( IoService, Protocol ),
+    Socket( *io_serv, Protocol ),
     NetInterface( source_network_interface, Socket ),
-    IcmpPacketReceiveTimer( IoService ),
+    IcmpPacketReceiveTimer( *io_serv ),
     Identifier( 0 ),
     SequenceNumber( 0 ),
     TimeSent( microsec_clock::universal_time() ),
@@ -162,6 +161,9 @@ void IcmpPinger::send_echo_request( const IcmpPacketItem icmp_packet )
     // Send the request
     try
     {
+        GlobalLogger.info()
+                    << DestinationEndpoint.address().to_string()
+                    << ": sending ping" << endl;
         const_buffers_1 data = request_buffer.data();
         // Block until send the data
         size_t bytes_sent = Socket.send_to( data, DestinationEndpoint );
index 5aa0547..ce0c0a7 100644 (file)
@@ -32,7 +32,7 @@ class IcmpPinger : public Pinger
 {
 public:
     IcmpPinger(
-            boost::asio::io_service &io_serv,
+            const IoServiceItem io_serv,
             const boost::asio::ip::icmp::socket::protocol_type &protocol,
             const std::string &source_network_interface,
             const int echo_reply_timeout_in_sec
@@ -60,8 +60,6 @@ private:
     void set_ping_status( PingStatus ping_status );
 
 private:
-    /// The IO service object, which has the loop event
-    boost::asio::io_service &IoService;
     /// The destination host
     boost::asio::ip::icmp::endpoint DestinationEndpoint;
     /// Network layer protocol used to ping, IPv4 or IPv6
index e7b8004..fa500a6 100644 (file)
@@ -26,14 +26,10 @@ on this file might be covered by the GNU General Public License.
 #include "boost_assert_handler.h"
 
 using namespace std;
-using boost::lock_guard;
-using boost::mutex;
 using boost::posix_time::microsec_clock;
 using boost::posix_time::ptime;
 using I2n::Logger::GlobalLogger;
 
-typedef lock_guard<mutex> mutex_lock_guard;
-
 //-----------------------------------------------------------------------------
 // LinkStatus
 //-----------------------------------------------------------------------------
@@ -63,8 +59,7 @@ LinkStatus::LinkStatus(
     CurrentLinkStatus( Status_Down ),
     CurrentNotificationStatus( NotificationStatus_NotReported ),
     TimeLinkStatusChanged( microsec_clock::universal_time() ),
-    StatusNotifierCmd( new StatusNotifierCommand( status_notifier_cmd ) ),
-    Mutex()
+    StatusNotifierCmd( new StatusNotifierCommand( status_notifier_cmd ) )
 {
     BOOST_ASSERT( 0 <= hosts_down_limit );
     BOOST_ASSERT( 0 <= link_up_interval_in_min );
@@ -87,8 +82,6 @@ void LinkStatus::notify_host_up( const string &host_address )
 {
     BOOST_ASSERT( !host_address.empty() );
 
-    mutex_lock_guard lock( Mutex );
-
     GlobalLogger.info() << "- Host up: " << host_address << endl;
 
     add_host_up( host_address );
@@ -114,8 +107,6 @@ void LinkStatus::notify_host_down( const string &host_address )
 {
     BOOST_ASSERT( !host_address.empty() );
 
-    mutex_lock_guard lock( Mutex );
-
     GlobalLogger.info() << "- Host down: " << host_address << endl;
 
     add_host_down( host_address );
index 4d47139..30d247c 100644 (file)
@@ -25,7 +25,6 @@ on this file might be covered by the GNU General Public License.
 
 #include <boost/asio.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/thread.hpp>
 
 #include "link/statusnotifiercommand.h"
 
@@ -112,8 +111,6 @@ public:
     boost::posix_time::ptime TimeLinkStatusChanged;
     /// Command used to notify the status of the link
     StatusNotifierCommandItem StatusNotifierCmd;
-    /// Mutual exclusion variable to avoid data races
-    boost::mutex Mutex;
 
 };
 
index 778c839..09881b9 100644 (file)
@@ -28,7 +28,7 @@ on this file might be covered by the GNU General Public License.
 #include <boost/shared_ptr.hpp>
 #include <boost/math/special_functions/round.hpp>
 #include <boost/numeric/conversion/cast.hpp>
-#include <boost/date_time/posix_time_types.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
 
 #include <daemonfunc.hpp>
 #include <logfunc.hpp>
@@ -45,13 +45,16 @@ on this file might be covered by the GNU General Public License.
 
 using namespace std;
 using boost::shared_ptr;
-using boost:posix::time_duration;
+using boost::posix_time::time_duration;
 using I2n::Logger::GlobalLogger;
 
 // a map from interval (in seconds) to delay (in seconds)
 typedef std::pair<int, float> IntervalCountPair;
 typedef std::map<int, float> DelayMap;
 typedef shared_ptr<boost::asio::io_service> IoServiceItem;
+typedef shared_ptr<boost::asio::deadline_timer> TimerItem;
+
+const boost::posix_time::time_duration SIGNAL_CHECK_INTERVAL = boost::posix_time::seconds(1);
 
 //-----------------------------------------------------------------------------
 // Declarations
@@ -62,12 +65,38 @@ LinkStatusItem get_status_notifier(const ConfigurationItem&);
 void init_logger();
 void set_log_output(const ConfigurationItem &);
 DelayMap calc_pinger_delays(const HostList &hosts);
-void init_pingers(const ConfigurationItem&, const LinkStatusItem&, PingSchedulerList*);
+void init_pingers(const IoServiceItem, const ConfigurationItem&, 
+                  const LinkStatusItem&, PingSchedulerList*);
 void start_pingers(const PingSchedulerList&);
 void stop_pingers(const PingSchedulerList&);
-void block_all_signals();
-void handle_signals(const int default_log_level);
 
+void signal_handler(int param);
+void signal_checker( const boost::system::error_code &error );
+void install_signal_handler( const IoServiceItem io_service, const int config_log_level );
+void reset_signal_handlers();
+
+// data required for signal handling (SIGINT, SIGTERM, ... )
+struct signal_data_struct
+{
+    sig_atomic_t signaled_flag;
+    IoServiceItem io_service;
+    void (*old_handler_int )(int);
+    void (*old_handler_term)(int);
+    void (*old_handler_usr1)(int);
+    void (*old_handler_usr2)(int);
+    bool stopped;
+    TimerItem check_timer;
+    int config_log_level;
+
+    signal_data_struct():
+        signaled_flag( false ),
+        io_service(),
+        stopped( false ),
+        check_timer(),
+        config_log_level( I2n::Logger::LogLevel::Notice )
+    { }
+
+};
 //-----------------------------------------------------------------------------
 // Definitions
 //-----------------------------------------------------------------------------
@@ -115,8 +144,9 @@ void init_logger()
     // set default: log at level NOTICE to syslog
     const int default_log_level = I2n::Logger::LogLevel::Notice;
 
-    I2n::Logger::enable_syslog( I2n::Logger::Facility::User ); //lint !e1786
-    I2n::Logger::set_log_level( default_log_level );           //lint !e534
+    I2n::Logger::enable_syslog( I2n::Logger::Facility::User );
+    I2n::Logger::enable_stderr_log( true );
+    I2n::Logger::set_log_level( default_log_level );
 }
 
 void set_log_output(
@@ -187,7 +217,7 @@ DelayMap calc_pinger_delays(const HostList &hosts)
 }
 
 void init_pingers(
-        IoServiceItem io_service,
+        const IoServiceItem io_service,
         const ConfigurationItem &configuration,
         const LinkStatusItem &status_notifier,
         PingSchedulerList *scheduler_list
@@ -254,13 +284,7 @@ void start_pingers(
 {
     // start each ping scheduler
     BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list )
-    {
-        bool started = scheduler->start_pinging_thread();
-        if ( !started )
-        {
-            GlobalLogger.error() << "Could not start pinger." << endl;
-        }
-    }
+        scheduler->start_pinging();
 }
 
 void stop_pingers(
@@ -271,129 +295,82 @@ void stop_pingers(
     GlobalLogger.info() << "Telling all pingers to stop";
     BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list )
     {
-        scheduler->stop_pinging_thread();
+        scheduler->stop_pinging();
     }
-
-    GlobalLogger.info() << "Waiting for threads to shut down";
-    BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list )
-    {
-        scheduler->wait_pinging_thread();
-    }
-    GlobalLogger.info() << "All ping threads are gone";
 }
 
-/**
- * @brief Block all signals so created threads inherit that signal mask.
- *
- * @return void
- **/
-void block_all_signals()
-{
-    sigset_t all_signals;
-    int result = sigfillset( &all_signals );
-    if ( result == -1 ) {
-        GlobalLogger.error() << "Sigfillset failed." << endl;
-    }
 
-    result = sigprocmask( SIG_SETMASK, &all_signals, NULL );
-    if ( result == -1 ) {
-        throw runtime_error( "Can't block signals" );
-    }
+// the one instance of signal_data_struct
+signal_data_struct signal_data;
+
+void signal_handler(int param)
+{
+    GlobalLogger.info() << "signal handler called with param " << param << endl;
+    signal_data.signaled_flag = param;
 }
 
-/**
- * @brief Wait until a signal receives and act upon it
- *
- * @param default_log_level
- *
- * @return void
- **/
-void handle_signals( const int default_log_level )
+void signal_checker( const boost::system::error_code &error )
 {
-    // Wait for signals
-    sigset_t all_signals;
-    int result = sigfillset( &all_signals );
-    if ( result == -1 ) {
-        GlobalLogger.error() << "Sigfillset failed." << endl;
-    }
+    bool want_stop = false;
 
-    // Synchronously process signals
-    bool want_quit = false;
-    while ( !want_quit )
-    {
-        int signal_number = 0;
-        int err = sigwait( &all_signals, &signal_number );
-        if (!err)
+    if ( error )
+    {   // there was an error in the timer
+        if ( error ==  boost::asio::error::operation_aborted )
         {
-            if ( signal_number == SIGUSR1 )
-            {
-                int new_log_level = I2n::Logger::get_log_level()+1;
-                I2n::Logger::set_log_level( new_log_level );                      //lint !e534
-                GlobalLogger.info() << "Increased log level to "
-                    << I2n::Logger::get_log_level_string();
-            }
-            else if ( signal_number == SIGUSR2 )
-            {
-                I2n::Logger::set_log_level( default_log_level );                                          //lint !e534
-                GlobalLogger.info() << "Reset log level to normal ("
-                    << I2n::Logger::get_log_level_string() << ")";
-            }
-            else if ( ( signal_number == SIGTERM ) || ( signal_number == SIGINT ))
-            {
-                want_quit = true;
-            }
+            GlobalLogger.error() << "Signal check timer was cancelled! Stopping io_service" << endl;
+            want_stop = true;
         }
         else
         {
-            want_quit = true;
+            GlobalLogger.error() << "not implemented yet! Stopping io_service" << endl;
+            want_stop = true;
         }
     }
-}
+    else if ( signal_data.signaled_flag )
+    {   // so there has been a signal --> check which one it was
 
-// data required for signal handling (SIGINT, SIGTERM, ... )
-struct signal_data_struct
-{
-    sig_atomic_t signaled_flag;
-    void (*old_handler_int )(int);
-    void (*old_handler_term)(int);
-    void (*old_handler_usr1)(int);
-    void (*old_handler_usr2)(int);
-    boost::asio::deadline_timer check_timer;
-    time_duration check_interval;
-    IoServiceItem io_service;
-};
-signal_data_struct signal_data;
+        // quickly copy and reset signal flag
+        sig_atomic_t signaled_flag = signal_data.signaled_flag;
+        signal_data.signaled_flag = 0;
 
-void signal_handler(int param)
-{
-    GlobalLogger.info() << "signal handler called with param " << param << endl;
-    signal_data.signaled_flag = param;
-}
+        if ( signaled_flag == SIGUSR1 )
+        {
+            int new_log_level = I2n::Logger::get_log_level()+1;
+            I2n::Logger::set_log_level( new_log_level );
+            GlobalLogger.info() << "Increased log level to "
+                << I2n::Logger::get_log_level_string();
+        }
+        else if ( signaled_flag == SIGUSR2 )
+        {
+            I2n::Logger::set_log_level( signal_data.config_log_level );
+            GlobalLogger.info() << "Reset log level to normal ("
+                << I2n::Logger::get_log_level_string() << ")";
+        }
+        else if ( ( signaled_flag == SIGTERM ) || ( signaled_flag == SIGINT ))
+        {
+            GlobalLogger.info() << "Received signal SIGINT/SIGTERM --> will stop" << endl;
+            want_stop = true;
+        }
+    }
 
-void signal_checker( const boost::system::error_code &error )
-{
-    GlobalLogger.debug() << "signal checker called with arg " << error;
-    if ( error )
-    if ( !signal_data.signaled_flag)
-    {   // schedule another timer
-        signal_data.check_timer.expires_from_now( signal_data.check_interval );
-        signal_data.check_timer.async_wait( signal_checker );
-        return;
+    if ( want_stop )
+    {   // interrupt infinite loop in main and asio event loop
+        signal_data.stopped = true;
+        signal_data.io_service->stop();
     }
     else
-    {
-        // so there has been a signal --> stop
-        // actually, see handle_signals for what to do
-        GlobalLogger.error() << "not implemented yet, see handle_signals for what to do!" 
-                             << endl;
-        signal_data.io_service->stop()
+    {   // re-schedule timer
+        GlobalLogger.debug() << "Setting another signal timer" << endl;
+        signal_data.check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL );
+        signal_data.check_timer->async_wait( signal_checker );
     }
 }
 
-bool install_signal_handler( IoServiceItem io_service,
-                             const time_duration &check_interval )
+/// register own signal handlers; see reset_signal_handlers for undo
+void install_signal_handler( const IoServiceItem io_service, const int config_log_level )
 {
     signal_data.signaled_flag = 0;
+    signal_data.config_log_level = config_log_level;
 
     // install own signal handlers
     signal_data.old_handler_int  = signal(SIGINT,  signal_handler);
@@ -404,28 +381,50 @@ bool install_signal_handler( IoServiceItem io_service,
           signal_data.old_handler_term == SIG_ERR ||
           signal_data.old_handler_usr1 == SIG_ERR ||
           signal_data.old_handler_usr2 == SIG_ERR )
-        throw runtime_error( "Failed to install signal handler: " + strerror(errno) );
+        throw runtime_error( string("Failed to install signal handler: ") + string(strerror(errno)) );
+
+    // create a timer and a shared pointer to it, so it does not get out of scope
+    TimerItem check_timer( new boost::asio::deadline_timer( *io_service ) );
 
-    // add timer to io_service that calls signal_checker
-    signal_data.check_interval = check_interval;
+    // remember the io_service and the timer
     signal_data.io_service = io_service;
-    signal_data.check_timer( io_service );
-    signal_data.check_timer.expires_from_now( check_interval );
+    signal_data.check_timer = check_timer;
 
-    // start timer
-    signal_data.check_timer.async_wait( signal_checker );
+    // set the timer
+    check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL );
+    check_timer->async_wait( signal_checker );
+    GlobalLogger.debug() << "signal timer set" << endl;
 }
 
-int main( int argc, const char *argv[] )
+/// reset handlers to the ones saved in install_signal_handler
+void reset_signal_handlers()
 {
-    // Block all signals before creating any threads
-    block_all_signals();
+    void (*old_handler_int)(int);
+    void (*old_handler_term)(int);
+    void (*old_handler_usr1)(int);
+    void (*old_handler_usr2)(int);
+    old_handler_int  = signal(SIGINT , signal_data.old_handler_int);
+    old_handler_term = signal(SIGTERM, signal_data.old_handler_term);
+    old_handler_usr1 = signal(SIGUSR1, signal_data.old_handler_usr1);
+    old_handler_usr2 = signal(SIGUSR2, signal_data.old_handler_usr2);
+
+    if (  old_handler_int  == SIG_ERR ||
+          old_handler_term == SIG_ERR ||
+          old_handler_usr1 == SIG_ERR ||
+          old_handler_usr2 == SIG_ERR )
+        throw runtime_error( string("Failed to reset signal handler: ") + string(strerror(errno)) );
+}
+
 
+int main( int argc, const char *argv[] )
+{
     init_logger();
     GlobalLogger.debug() << "logger initiated with default config";
 
     PingSchedulerList scheduler_list;
+    IoServiceItem io_service;
     int ret_code = 0;
+    unsigned n_exceptions = 0;
     try
     {
         ConfigurationItem configuration = get_configuration( argc, argv );
@@ -436,7 +435,7 @@ int main( int argc, const char *argv[] )
         }
 
         int log_level = configuration->get_log_level();
-        I2n::Logger::set_log_level( log_level );                                                    //lint !e534
+        I2n::Logger::set_log_level( log_level );
         GlobalLogger.info() << "Set LogLevel to " << I2n::Logger::get_log_level_string() << endl;
 
         set_log_output( configuration );
@@ -450,38 +449,47 @@ int main( int argc, const char *argv[] )
 
         LinkStatusItem status_notifier = get_status_notifier( configuration );
 
-        IoServiceItem io_service( new boost::asio::io_service() );
+        IoServiceItem io_service_temp( new boost::asio::io_service() );
+        io_service_temp.swap( io_service );
+        io_service_temp.reset();
 
         init_pingers( io_service, configuration, status_notifier, &scheduler_list );
 
-        //start_pingers( scheduler_list );
-
-        install_signal_handler( io_service );
+        install_signal_handler( io_service, log_level );
 
+        start_pingers( scheduler_list );
     }
     catch ( const std::exception &ex )
     {
         GlobalLogger.error() << "Uncaught exception. " << ex.what() << endl;
         ret_code = 1;
+        ++n_exceptions;
     }
     catch (...) {
         GlobalLogger.error() << "Caught unknown exception!" << endl;
         ret_code = 2;
+        ++n_exceptions;
     }
 
-    // call boost::asio main event loop, ignoring exceptions
-    while ( true )
+    if ( ret_code == 0 )
     {
-        try
+        // call boost::asio main event loop, catching exceptions
+        while ( !signal_data.stopped )
         {
-            io_service->run();
-        }
-        catch ( const std::exception &ex )
-        {
-            GlobalLogger.error() << "Caught exception, will continue. " << ex.what() << endl;
-        }
-        catch (...) {
-            GlobalLogger.error() << "Caught unknown exception, will continue!" << endl;
+            try
+            {
+                GlobalLogger.info() << "starting/continuing io_service main loop" << endl;
+                io_service->run();
+            }
+            catch ( const std::exception &ex )
+            {
+                ++n_exceptions;
+                GlobalLogger.error() << "Caught exception, will continue. " << ex.what() << endl;
+            }
+            catch (...) {
+                ++n_exceptions;
+                GlobalLogger.error() << "Caught unknown exception, will continue!" << endl;
+            }
         }
     }
 
@@ -490,6 +498,7 @@ int main( int argc, const char *argv[] )
     {
         GlobalLogger.info() << "Cleaning up" << endl;
         stop_pingers( scheduler_list );
+        reset_signal_handlers();
     }
     catch ( const std::exception &ex )
     {
@@ -501,6 +510,7 @@ int main( int argc, const char *argv[] )
         ret_code += 8;
     }
 
-    GlobalLogger.notice() << "Pingcheck done" << endl;
+    GlobalLogger.notice() << "Pingcheck done " << endl;
+    GlobalLogger.debug() << "In main loop, had " << n_exceptions << " exception[s]" << endl;
     return ret_code;
 }
index ade4d30..fa99849 100644 (file)
@@ -66,17 +66,16 @@ using I2n::Logger::GlobalLogger;
  * @param echo_reply_timeout_in_sec The amount of time to wait for a reply.
  */
 TcpPinger::TcpPinger(
-        io_service &io_serv,
+        const IoServiceItem io_serv,
         const tcp_raw_protocol::socket::protocol_type &protocol,
         const string &source_network_interface_name,
         const int rst_reply_timeout_in_sec
 ) :
-    IoService( io_serv ),
     DestinationEndpoint(),
     Protocol( protocol ),
-    Socket( IoService, Protocol ),
+    Socket( *io_serv, Protocol ),
     NetInterface( source_network_interface_name, Socket ),
-    TcpSegmentReceiveTimer( IoService ),
+    TcpSegmentReceiveTimer( *io_serv ),
     Identifier( 0 ),
     SequenceNumber( 0 ),
     TimeSent( microsec_clock::universal_time() ),
index 914322c..690fe29 100644 (file)
@@ -45,7 +45,7 @@ class TcpPinger : public Pinger
 {
 public:
     TcpPinger(
-            boost::asio::io_service &io_serv,
+            const IoServiceItem io_serv,
             const boost::asio::ip::tcp_raw_protocol::socket::protocol_type &protocol,
             const std::string &source_network_interface_name,
             const int rst_reply_timeout_in_sec
@@ -81,8 +81,6 @@ private:
     void set_ping_status( PingStatus ping_status );
 
 private:
-    /// IO service object, which has the loop event
-    boost::asio::io_service &IoService;
     /// The destination host
     boost::asio::ip::tcp_raw_protocol::endpoint DestinationEndpoint;
     /// Network layer protocol used to ping, IPv4 or IPv6