temp commit before leaving, started to change signal handling and use singel io_service
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Tue, 23 Dec 2014 17:42:23 +0000 (18:42 +0100)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Tue, 23 Dec 2014 17:42:23 +0000 (18:42 +0100)
src/host/pinger.h
src/host/pingrotate.cpp
src/host/pingrotate.h
src/host/pingscheduler.cpp
src/main.cpp

index 203e585..7355637 100644 (file)
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/utility.hpp>
+#include <boost/asio/io_service.hpp>
+
+//-----------------------------------------------------------------------------
+// IoServiceItem
+//-----------------------------------------------------------------------------
+
+typedef boost::shared_ptr<boost::asio::io_service> IoServiceItem;
 
 //-----------------------------------------------------------------------------
 // Pinger
index 9ad8987..598fb5c 100644 (file)
@@ -48,7 +48,7 @@ using boost::shared_ptr;
  * host. The protocols will be used in the order they are in the list.
  */
 PingRotate::PingRotate(
-        io_service &io_serv,
+        IoServiceItem io_serv,
         const string &network_interface,
         const string &destination_address,
         const uint16_t destination_port,
index e5a68c9..078b91b 100644 (file)
@@ -46,7 +46,7 @@ class PingRotate
 {
 public:
     PingRotate(
-            boost::asio::io_service &io_serv,
+            IoServiceItem io_serv,
             const std::string &network_interface,
             const std::string &destination_address,
             const uint16_t destination_port,
@@ -83,7 +83,7 @@ private:
     //
 
     /// The IO service object, which has the loop event
-    boost::asio::io_service &IoService;
+    IoServiceItem IoService;
     /// The network interface name
     std::string NetworkInterfaceName;
     /// The list of IPs which are aliases to the host DNS
index bced749..ca07c15 100644 (file)
@@ -61,6 +61,7 @@ using I2n::Logger::GlobalLogger;
  * @param first_delay Delay in seconds from start_pinging_thread to first ping attempt
  */
 PingScheduler::PingScheduler(
+        IoServiceItem io_service,
         const string &network_interface,
         const string &destination_address,
         const uint16_t destination_port,
@@ -75,9 +76,9 @@ PingScheduler::PingScheduler(
         const int first_delay
 
 ) :
-    IoService(),
-    NextPingTimer( IoService ),
-    NextAddressTimer( IoService ),
+    IoService( io_service ),
+    NextPingTimer( io_service ),
+    NextAddressTimer( io_service ),
     TimeSentLastPing( microsec_clock::universal_time() ),
     PingIntervalInSec( ping_interval_in_sec ),
     AddressResolveIntervalInSec( ping_interval_in_sec ),
index 0416b24..778c839 100644 (file)
@@ -28,6 +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 <daemonfunc.hpp>
 #include <logfunc.hpp>
@@ -43,13 +44,14 @@ on this file might be covered by the GNU General Public License.
 
 
 using namespace std;
-using boost::asio::io_service;
 using boost::shared_ptr;
+using boost:posix::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;
 
 //-----------------------------------------------------------------------------
 // Declarations
@@ -185,6 +187,7 @@ DelayMap calc_pinger_delays(const HostList &hosts)
 }
 
 void init_pingers(
+        IoServiceItem io_service,
         const ConfigurationItem &configuration,
         const LinkStatusItem &status_notifier,
         PingSchedulerList *scheduler_list
@@ -226,6 +229,7 @@ void init_pingers(
 
         PingSchedulerItem scheduler(
                 new PingScheduler(
+                        io_service,
                         network_interface,
                         destination_address,
                         destination_port,
@@ -254,8 +258,7 @@ void start_pingers(
         bool started = scheduler->start_pinging_thread();
         if ( !started )
         {
-            GlobalLogger.error() << "Error: could not start pinger."
-                    << endl;
+            GlobalLogger.error() << "Could not start pinger." << endl;
         }
     }
 }
@@ -289,7 +292,7 @@ void block_all_signals()
     sigset_t all_signals;
     int result = sigfillset( &all_signals );
     if ( result == -1 ) {
-        GlobalLogger.error() << "Error: sigfillset failed." << endl;
+        GlobalLogger.error() << "Sigfillset failed." << endl;
     }
 
     result = sigprocmask( SIG_SETMASK, &all_signals, NULL );
@@ -311,7 +314,7 @@ void handle_signals( const int default_log_level )
     sigset_t all_signals;
     int result = sigfillset( &all_signals );
     if ( result == -1 ) {
-        GlobalLogger.error() << "Error: sigfillset failed." << endl;
+        GlobalLogger.error() << "Sigfillset failed." << endl;
     }
 
     // Synchronously process signals
@@ -347,6 +350,72 @@ void handle_signals( const int default_log_level )
     }
 }
 
+// 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;
+
+void signal_handler(int param)
+{
+    GlobalLogger.info() << "signal handler called with param " << param << endl;
+    signal_data.signaled_flag = param;
+}
+
+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;
+    }
+    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()
+    }
+}
+
+bool install_signal_handler( IoServiceItem io_service,
+                             const time_duration &check_interval )
+{
+    signal_data.signaled_flag = 0;
+
+    // install own signal handlers
+    signal_data.old_handler_int  = signal(SIGINT,  signal_handler);
+    signal_data.old_handler_term = signal(SIGTERM, signal_handler);
+    signal_data.old_handler_usr1 = signal(SIGUSR1, signal_handler);
+    signal_data.old_handler_usr2 = signal(SIGUSR2, signal_handler);
+    if (  signal_data.old_handler_int  == SIG_ERR ||
+          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) );
+
+    // add timer to io_service that calls signal_checker
+    signal_data.check_interval = check_interval;
+    signal_data.io_service = io_service;
+    signal_data.check_timer( io_service );
+    signal_data.check_timer.expires_from_now( check_interval );
+
+    // start timer
+    signal_data.check_timer.async_wait( signal_checker );
+}
+
 int main( int argc, const char *argv[] )
 {
     // Block all signals before creating any threads
@@ -360,57 +429,78 @@ int main( int argc, const char *argv[] )
     try
     {
         ConfigurationItem configuration = get_configuration( argc, argv );
-        if ( configuration.get() != NULL )
+        if ( configuration.get() == NULL )
         {
-            int log_level = configuration->get_log_level();
-            I2n::Logger::set_log_level( log_level );                                                    //lint !e534
-            GlobalLogger.info() << "Set LogLevel to " << I2n::Logger::get_log_level_string() << endl;
+            GlobalLogger.error() << "no configuration!";
+            return 1;
+        }
 
-            set_log_output( configuration );
-            GlobalLogger.notice() << "started";
+        int log_level = configuration->get_log_level();
+        I2n::Logger::set_log_level( log_level );                                                    //lint !e534
+        GlobalLogger.info() << "Set LogLevel to " << I2n::Logger::get_log_level_string() << endl;
 
-            bool daemon_mode = configuration->get_daemon();
-            if ( daemon_mode )
-            {
-                I2n::Daemon::daemonize();
-            }
+        set_log_output( configuration );
+        GlobalLogger.notice() << "started";
 
-            LinkStatusItem status_notifier = get_status_notifier( configuration );
+        bool daemon_mode = configuration->get_daemon();
+        if ( daemon_mode )
+        {
+            I2n::Daemon::daemonize();
+        }
 
-            init_pingers( configuration, status_notifier, &scheduler_list );
+        LinkStatusItem status_notifier = get_status_notifier( configuration );
 
-            start_pingers( scheduler_list );
+        IoServiceItem io_service( new boost::asio::io_service() );
+
+        init_pingers( io_service, configuration, status_notifier, &scheduler_list );
+
+        //start_pingers( scheduler_list );
+
+        install_signal_handler( io_service );
 
-            // React to signals (main thread will sleep)
-            handle_signals( log_level );
-        }
     }
     catch ( const std::exception &ex )
     {
-        GlobalLogger.error() << "Error: uncaught exception. " << ex.what() << endl;
+        GlobalLogger.error() << "Uncaught exception. " << ex.what() << endl;
         ret_code = 1;
     }
     catch (...) {
-        GlobalLogger.error() << "Error: caught unknown exception!" << endl;
+        GlobalLogger.error() << "Caught unknown exception!" << endl;
         ret_code = 2;
     }
 
+    // call boost::asio main event loop, ignoring exceptions
+    while ( true )
+    {
+        try
+        {
+            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;
+        }
+    }
+
     // clean up
     try
     {
         GlobalLogger.info() << "Cleaning up" << endl;
         stop_pingers( scheduler_list );
-        GlobalLogger.notice() << "exiting";
     }
     catch ( const std::exception &ex )
     {
-        GlobalLogger.error() << "Error: uncaught exception while cleaning up " << ex.what() << endl;
+        GlobalLogger.error() << "Uncaught exception while cleaning up: " << ex.what() << endl;
         ret_code += 4;
     }
     catch (...) {
-        GlobalLogger.error() << "Error: caught unknown exception while cleaning up!" << endl;
+        GlobalLogger.error() << "Caught unknown exception while cleaning up!" << endl;
         ret_code += 8;
     }
 
+    GlobalLogger.notice() << "Pingcheck done" << endl;
     return ret_code;
 }