Fix 'occurred' typo
[bpdyndnsd] / src / main.cpp
index 0341aec..4fcf1ed 100644 (file)
 #include <config.h>
 #endif
 
-#define VERSION     0
-#define REVISION    1
-#define RELEASE     0
-
-#define PIDFILE "/var/run/bpdyndnsd.pid"
+#define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid"
 
 #include <iostream>
+#include <fstream>
 #include <list>
 #include <string>
-
 #include <boost/foreach.hpp>
-
-#include "updater.cpp"
-#include "config.cpp"
-#include "logger.cpp"
-
-#include "service.cpp"
-
-#include "dhs.cpp"
-#include "ods.cpp"
-
 #include <sys/types.h>
 #include <signal.h>
 
+#include "updater.hpp"
 
 using namespace std;
 
-typedef boost::shared_ptr<Updater> UpdaterPtr;
-
-UpdaterPtr updater;
-bool online_mode = 1;
+Updater::Ptr updater;
+volatile bool caught_sig_hup = false;
+volatile bool caught_sig_usr1 = false;
+volatile bool caught_sig_usr2 = false;
+volatile bool caught_sig_rtmin = false;
+volatile bool caught_sig_rtmax = false;
+volatile bool caught_sig_term = false;
 
 /**
  * Checks if a bpdyndnsd process is already running.
@@ -77,73 +67,244 @@ int check_for_running_process()
  * Writes the pid into the pidfile.
  * @param pid The process's pid.
  */
-void write_pidfile(int pid)
+int write_pidfile(int pid)
 {
     ofstream pidfile(PIDFILE);
     if ( pidfile.is_open() )
     {
         pidfile << pid << endl;
     }
+    else
+    {
+        updater->get_logger()->print_error_opening_rw(PIDFILE);
+        return -1;
+    }
     pidfile.close();
+    return 0;
 }
 
 
 /**
- * Signal SIGTERM caught, releasing resources and exit.
- * @param param Parameter from the signal interface.
+ * Parent shutdown function
+ * @return 0 if all is fine, -1 otherwise
  */
-void terminate(int param)
+int shutdown_parent(bool remove_pid, int ret_val)
 {
-    updater->get_logger()->print_caught_sigterm();
+    // starting shutdown_parent
+    updater->get_logger()->print_starting_shutdown_parent();
+
+    // remove pidfile if requested
+    if(remove_pid)
+        unlink(PIDFILE);
+
+    // shutdown parent complete
+    updater->get_logger()->print_shutdown_parent_succeeded();
+
+    // release shared pointer
     updater.reset();
-    exit(1);
+
+    exit(ret_val);
 }
 
 
 /**
- * Signal SIGUSR1 caught, switching to offline mode.
- * @param param Parameter from the signal interface.
+ * Shutdown function
+ * @return 0 if all is fine, -1 otherwise
  */
-void switch_to_offline(int param)
+int shutdown()
 {
-    updater->get_logger()->print_caught_siguser1();
-    online_mode = 0;
+    int ret_val = 0;
+
+    // starting shutdown
+    updater->get_logger()->print_starting_shutdown();
+
+    // serialize actual service objects
+    if ( updater->get_service_holder()->serialize_services() != 0 )
+        ret_val = -1;
+
+    // unlink pidfile
+    unlink(PIDFILE);
+
+    // shutdown complete
+    updater->get_logger()->print_shutdown_succeeded();
+
+    // release shared pointer
+    updater.reset();
+
+    return ret_val;
 }
 
 
 /**
- * Signal SIGHUP caught, reloading config and switching to online mode.
- * @param param 
+ * Signal SIGTERM caught (exit program)
+ * @param param Parameter from the signal interface.
  */
-void reload_config(int param)
+void sigterm_func(int param)
 {
-    updater->get_logger()->print_caught_sighup();
-    updater->reload_config();
-    online_mode = 1;
-}
+    caught_sig_term = true;
+} /*lint !e715 */
+
+
+/**
+ * Signal SIGUSR1 caught (switch to offline mode)
+ * @param param Parameter from the signal interface.
+ */
+void sigusr1_func(int param)
+{
+    caught_sig_usr1 = true;
+} /*lint !e715 */
+
+
+/**
+ * Signal SIGHUP caught (reload config and reset log level)
+ * @param param Parameter from the signal interface.
+ */
+void sighup_func(int param)
+{
+    caught_sig_hup = true;
+} /*lint !e715 */
+
+
+/**
+ * Signal SIGUSR2 caught (switch to online mode)
+ * @param param Parameter from the signal interface.
+ */
+void sigusr2_func(int param)
+{
+    caught_sig_usr2 = true;
+} /*lint !e715 */
+
+
+/**
+ * Signal SIGRTMIN caught (switch to online mode with webcheck enabled)
+ * @param param Parameter from the signal interface.
+ */
+void sigrtmin_func(int param)
+{
+    caught_sig_rtmin = true;
+} /*lint !e715 */
+
+
+/**
+ * Signal SIGRTMAX caught (increase log level)
+ * @param param Parameter from the signal interface.
+ */
+void sigrtmax_func(int param)
+{
+    caught_sig_rtmax = true;
+} /*lint !e715 */
 
 
 /**
  * Initialize the signals we handle.
+ * @return 0 if all is fine, -1 on error.
  */
 int init_signals()
 {
     sighandler_t ret_val;
-    ret_val = signal(SIGTERM,terminate);
+    ret_val = signal(SIGTERM, sigterm_func);
+    if ( ret_val == SIG_ERR )
+    {
+        updater->get_logger()->print_error_setting_signal("SIGTERM");
+        return -1;
+    }
+    ret_val = signal(SIGUSR1, sigusr1_func);
+    if ( ret_val == SIG_ERR )
+    {
+        updater->get_logger()->print_error_setting_signal("SIGUSR1");
+        return -1;
+    }
+    ret_val = signal(SIGHUP, sighup_func);
     if ( ret_val == SIG_ERR )
+    {
+        updater->get_logger()->print_error_setting_signal("SIGHUP");
         return -1;
-    ret_val = signal(SIGUSR1,switch_to_offline);
+    }
+    ret_val = signal(SIGUSR2, sigusr2_func);
     if ( ret_val == SIG_ERR )
+    {
+        updater->get_logger()->print_error_setting_signal("SIGUSR2");
         return -1;
-    ret_val = signal(SIGHUP,reload_config);
+    }
+    ret_val = signal(SIGRTMIN, sigrtmin_func);
     if ( ret_val == SIG_ERR )
+    {
+        updater->get_logger()->print_error_setting_signal("SIGRTMIN");
+        return -1;
+    }
+    ret_val = signal(SIGRTMAX, sigrtmax_func);
+    if ( ret_val == SIG_ERR )
+    {
+        updater->get_logger()->print_error_setting_signal("SIGRTMAX");
         return -1;
+    }
 
     return 0;
 }
 
 
 /**
+ * Try to run in daemon mode if enabled in config.
+ * @param daemon_mode True if process should detach to init (run as daemon), false if not detach to init.
+ * @return 0 if all is fine, -1 on error.
+ */
+int init_daemon_mode(bool daemon_mode)
+{
+    updater->get_logger()->print_daemon_mode(daemon_mode);
+    if ( daemon_mode == true )
+    {
+        int pid = fork();
+        if ( pid < 0 )
+        {
+            // error fork
+            updater->get_logger()->print_error_fork();
+            return -1;
+        }
+        else if ( pid > 0 )
+        {
+            // parent continues here
+            if ( write_pidfile(pid) != 0 )
+            {
+                if ( kill(pid,SIGTERM) != 0 )
+                {
+                    updater->get_logger()->print_error_kill_child(pid);
+                    shutdown_parent(false,-1); /*lint !e534 */
+                }
+                else
+                {
+                    updater->get_logger()->print_child_killed(pid);
+                    shutdown_parent(true,-1); /*lint !e534 */
+                }
+            }
+            updater->get_logger()->print_runnig_as_daemon(pid);
+            shutdown_parent(false,0); /*lint !e534 */
+        }
+        // child starts here
+    }
+    else
+    {
+        if ( write_pidfile(getpid()) != 0 )
+        {
+            shutdown(); /*lint !e534 */
+            exit(-1);
+        }
+    }
+    return 0;
+}
+
+/**
+ * Calculate how long the dialup mode burst period will last (dialup mode only)
+ * @return Timestamp until dialup period lasts or zero if dialup mode is disabled
+*/
+time_t calc_dialup_mode_burst_period()
+{
+    if (updater->get_config()->get_dialup_mode() )
+        return time(NULL) + updater->get_config()->get_dialup_burst_period_seconds();
+
+    return 0;
+}
+
+/**
  * @brief The main part.
  * @param argc Number of arguments
  * @param argv Command line arguments
@@ -152,68 +313,140 @@ int init_signals()
 int main(int argc, char *argv[])
 {
     // initialize Updater
-    UpdaterPtr _updater(new Updater);
-    updater = _updater;
-    _updater.reset();
+    updater = Updater::Ptr(new Updater);
 
-    // load the cmd options
-    if ( updater->init_config_from_cmd(argc,argv) != 0 )
-        return 0;
-
-    // load the config and service files
-    if ( updater->init_config_from_files() != 0 )
-        return 0;
+    // load config and initialize helper classes
+    if ( updater->load_config(argc,argv) != 0 )
+        return -1;
 
     // open pidfile and check for running process
     if ( check_for_running_process() != 0)
-        return 0;
+        return -1;
 
     // init signal handling
     if ( init_signals() != 0)
-    {
-        updater->get_logger()->print_error_setting_signal();
-        return 0;
-    }
+        return -1;
 
-    // initialize daemon mode if configured
-    updater->get_logger()->print_daemon_mode(updater->get_config()->get_daemon_mode());
-    if ( updater->get_config()->get_daemon_mode() == 1 )
-    {
-        int pid = fork();
-        if ( pid < 0 )
-        {
-            // error fork
-            updater->get_logger()->print_error_fork();
-            return 0;
-        }
-        else if ( pid > 0 )
-        {
-            // parent
-            write_pidfile(pid);
-            updater->get_logger()->print_runnig_as_daemon(pid);
-            return 0;
-        }
-        // child starts here
-    }
+    // init daemon_mode if enabled
+    if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
+        return -1;
+
+    // Should we start in offline mode?
+    bool old_online_state = false;
+    bool is_online = !updater->get_config()->get_start_offline();
+    bool webcheck_enabled = updater->get_config()->get_webcheck_enabled();
+    bool exit_now = false;
+
+    // One shot run if daemon mode is disabled
+    if (updater->get_config()->get_daemon_mode() != 1)
+        exit_now = true;
 
+    // Tell the world we are running
+    updater->get_logger()->print_started();
+
+    int original_log_level = updater->get_logger()->get_loglevel();
+
+    // Dialup mode: Sleep a specified number of seconds between network traffic
+    time_t dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
+    time_t dialup_mode_sleep_until = 0;
 
     // service processing starts here
     do
     {
-        if ( online_mode == 1 )
+        // Signal processing
+        if (caught_sig_usr1)
+        {
+            caught_sig_usr1 = false;
+            updater->get_logger()->print_caught_siguser1();
+
+            // Go offline
+            is_online = false;
+        } else if (caught_sig_usr2)
+        {
+            caught_sig_usr2 = false;
+            updater->get_logger()->print_caught_siguser2();
+
+            // Go online
+            is_online = true;
+            webcheck_enabled = false;
+            dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
+        } else if (caught_sig_rtmin)
+        {
+            caught_sig_rtmin = false;
+            updater->get_logger()->print_caught_sigrtmin();
+
+            // Go online - with webcheck
+            is_online = true;
+            webcheck_enabled = true;
+            dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
+        } else if (caught_sig_rtmax)
+        {
+            caught_sig_rtmax = false;
+
+            // Increase log level
+            int new_loglevel = updater->get_logger()->get_loglevel() + 1;
+            updater->get_logger()->print_caught_sigrtmax(new_loglevel);
+            updater->get_logger()->set_loglevel(new_loglevel);
+        } else if (caught_sig_term)
+        {
+            caught_sig_term = false;
+            updater->get_logger()->print_caught_sigterm();
+
+            exit_now = true;
+        } else if (caught_sig_hup)
         {
-            // update all configured services
-            updater->update_services();
+            caught_sig_hup = false;
+            updater->get_logger()->print_caught_sighup();
+
+            if ( updater->reload_config() != 0 )
+            {
+                updater->get_logger()->print_conf_reload_failed_exit();
+                exit(-1);
+            }
+
+            // Reset log level to startup log level in case it got elevated by SIGRTMAX
+            updater->get_logger()->set_loglevel(original_log_level);
+
+            // Reset dialup mode burst period on config reload
+            dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
+        }
+
+        // State handling
+        if ( is_online == true )
+        {
+            // Check if webcheck_enabled differs due to caught singnal then set it in config correspondingly
+            if ( updater->get_config()->get_webcheck_enabled() != webcheck_enabled )    /*lint !e731 */
+                updater->get_config()->set_webcheck_enabled(webcheck_enabled);
+
+            if (updater->get_config()->get_dialup_mode() == false ||
+                (time(NULL) > dialup_mode_sleep_until || time(NULL) < dialup_mode_burst_mode_until) )
+            {
+                // update all configured services
+                updater->update_services(is_online != old_online_state);
+
+                // Refresh sleep state (dialup mode only)
+                dialup_mode_sleep_until = time(NULL) + updater->get_config()->get_dialup_sleep_seconds();
+            } else
+                updater->get_logger()->print_sleep_dialup_mode(dialup_mode_sleep_until);
         }
         else
         {
+            // We are in offline mode, do nothing, expect printing "offline mode".
             updater->get_logger()->print_offline_mode();
         }
 
-        if ( updater->get_config()->get_daemon_mode() == 1 )
-            sleep(10);  // TODO: in a final release, correct the sleep value to something suitable
+        // Keep old online state so we can determine
+        // if we switched from offline to online
+        old_online_state = is_online;
 
-    }while ( updater->get_config()->get_daemon_mode() == 1 );
+        // Snore, snore... don't hog the cpu if we are in daemon_mode.
+        if ( !exit_now )
+            sleep(10); /*lint !e534 */
+    } while ( !exit_now );
+
+    // Serialize services to save their actual state.
+    if ( shutdown() != 0 )
+        return -1;
 
     return 0;
 }