/** @file * @brief The main function. * * * * @copyright Intra2net AG * @license GPLv2 */ #ifdef HAVE_CONFIG_H #include #endif #define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid" #include #include #include #include #include #include #include #include "updater.hpp" using namespace std; 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); } /** * 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. * @param argc Number of arguments * @param argv Command line arguments * @return 0 if all is fine. */ int main(int argc, char *argv[]) { // initialize 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(); } // 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(); } // Keep old online state so we can determine // if we switched from offline to online old_online_state = is_online; // 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; }