#include <config.h>
#endif
-#define VERSION 0
-#define REVISION 1
-#define RELEASE 0
+#define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid"
#include <iostream>
+#include <fstream>
#include <list>
#include <string>
-
#include <boost/foreach.hpp>
+#include <sys/types.h>
+#include <signal.h>
-#include "updater.cpp"
-#include "config.cpp"
-#include "logger.cpp"
+#include "updater.hpp"
-#include "service.cpp"
+using namespace std;
-#include "dhs.cpp"
-#include "ods.cpp"
+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.
+ * @param updater Shared Pointer to updater, needed for logging.
+ * @return 0 if process not running already or pid of already running process.
+ */
+int check_for_running_process()
+{
+ ifstream pidfile(PIDFILE);
+ if ( pidfile.is_open() )
+ {
+ int pid;
+ pidfile >> pid;
+ if ( pid > 0 )
+ updater->get_logger()->print_pid_found(pid);
+ else
+ return 0;
+
+ // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running
+ if ( kill(pid,0) == 0)
+ {
+ updater->get_logger()->print_process_already_running(pid);
+ pidfile.close();
+ return pid;
+ }
+ }
+ pidfile.close();
+ return 0;
+}
+
+
+/**
+ * Writes the pid into the pidfile.
+ * @param pid The process's 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;
+}
+
+
+/**
+ * Parent shutdown function
+ * @return 0 if all is fine, -1 otherwise
+ */
+int shutdown_parent(bool remove_pid, int ret_val)
+{
+ // 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(ret_val);
+}
-using namespace std;
-typedef boost::shared_ptr<Updater> UpdaterPtr;
+/**
+ * Shutdown function
+ * @return 0 if all is fine, -1 otherwise
+ */
+int shutdown()
+{
+ 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 SIGTERM caught (exit program)
+ * @param param Parameter from the signal interface.
+ */
+void sigterm_func(int param)
+{
+ 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, 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(SIGUSR2, sigusr2_func);
+ if ( ret_val == SIG_ERR )
+ {
+ updater->get_logger()->print_error_setting_signal("SIGUSR2");
+ return -1;
+ }
+ 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.
int main(int argc, char *argv[])
{
// initialize Updater
- UpdaterPtr updater(new Updater);
+ updater = Updater::Ptr(new Updater);
+
+ // 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 -1;
+
+ // init signal handling
+ if ( init_signals() != 0)
+ return -1;
+
+ // 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
+ {
+ // 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)
+ {
+ 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();
+ }
- // load the cmd options
- if ( updater->init_config_from_cmd(argc,argv) != 0 )
- return 0;
+ // 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);
- // load the config and service files
- if ( updater->init_config_from_files() != 0 )
- return 0;
+ 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);
- cout << "Loglevel: " << updater->get_config()->get_loglevel() << endl;
+ // 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();
+ }
- // set the configured loggin facility, default stdout
+ // Keep old online state so we can determine
+ // if we switched from offline to online
+ old_online_state = is_online;
- // initialize daemon mode if configured
+ // Snore, snore... don't hog the cpu if we are in daemon_mode.
+ if ( !exit_now )
+ sleep(10); /*lint !e534 */
+ } while ( !exit_now );
- // update all configured services
- updater->update_services();
+ // Serialize services to save their actual state.
+ if ( shutdown() != 0 )
+ return -1;
return 0;
}