Fix 'occurred' typo
[bpdyndnsd] / src / main.cpp
1 /** @file
2  * @brief The main function.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid"
15
16 #include <iostream>
17 #include <fstream>
18 #include <list>
19 #include <string>
20 #include <boost/foreach.hpp>
21 #include <sys/types.h>
22 #include <signal.h>
23
24 #include "updater.hpp"
25
26 using namespace std;
27
28 Updater::Ptr updater;
29 volatile bool caught_sig_hup = false;
30 volatile bool caught_sig_usr1 = false;
31 volatile bool caught_sig_usr2 = false;
32 volatile bool caught_sig_rtmin = false;
33 volatile bool caught_sig_rtmax = false;
34 volatile bool caught_sig_term = false;
35
36 /**
37  * Checks if a bpdyndnsd process is already running.
38  * @param updater Shared Pointer to updater, needed for logging.
39  * @return 0 if process not running already or pid of already running process.
40  */
41 int check_for_running_process()
42 {
43     ifstream pidfile(PIDFILE);
44     if ( pidfile.is_open() )
45     {
46         int pid;
47         pidfile >> pid;
48         if ( pid > 0 )
49             updater->get_logger()->print_pid_found(pid);
50         else
51             return 0;
52
53         // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running
54         if ( kill(pid,0) == 0)
55         {
56             updater->get_logger()->print_process_already_running(pid);
57             pidfile.close();
58             return pid;
59         }
60     }
61     pidfile.close();
62     return 0;
63 }
64
65
66 /**
67  * Writes the pid into the pidfile.
68  * @param pid The process's pid.
69  */
70 int write_pidfile(int pid)
71 {
72     ofstream pidfile(PIDFILE);
73     if ( pidfile.is_open() )
74     {
75         pidfile << pid << endl;
76     }
77     else
78     {
79         updater->get_logger()->print_error_opening_rw(PIDFILE);
80         return -1;
81     }
82     pidfile.close();
83     return 0;
84 }
85
86
87 /**
88  * Parent shutdown function
89  * @return 0 if all is fine, -1 otherwise
90  */
91 int shutdown_parent(bool remove_pid, int ret_val)
92 {
93     // starting shutdown_parent
94     updater->get_logger()->print_starting_shutdown_parent();
95
96     // remove pidfile if requested
97     if(remove_pid)
98         unlink(PIDFILE);
99
100     // shutdown parent complete
101     updater->get_logger()->print_shutdown_parent_succeeded();
102
103     // release shared pointer
104     updater.reset();
105
106     exit(ret_val);
107 }
108
109
110 /**
111  * Shutdown function
112  * @return 0 if all is fine, -1 otherwise
113  */
114 int shutdown()
115 {
116     int ret_val = 0;
117
118     // starting shutdown
119     updater->get_logger()->print_starting_shutdown();
120
121     // serialize actual service objects
122     if ( updater->get_service_holder()->serialize_services() != 0 )
123         ret_val = -1;
124
125     // unlink pidfile
126     unlink(PIDFILE);
127
128     // shutdown complete
129     updater->get_logger()->print_shutdown_succeeded();
130
131     // release shared pointer
132     updater.reset();
133
134     return ret_val;
135 }
136
137
138 /**
139  * Signal SIGTERM caught (exit program)
140  * @param param Parameter from the signal interface.
141  */
142 void sigterm_func(int param)
143 {
144     caught_sig_term = true;
145 } /*lint !e715 */
146
147
148 /**
149  * Signal SIGUSR1 caught (switch to offline mode)
150  * @param param Parameter from the signal interface.
151  */
152 void sigusr1_func(int param)
153 {
154     caught_sig_usr1 = true;
155 } /*lint !e715 */
156
157
158 /**
159  * Signal SIGHUP caught (reload config and reset log level)
160  * @param param Parameter from the signal interface.
161  */
162 void sighup_func(int param)
163 {
164     caught_sig_hup = true;
165 } /*lint !e715 */
166
167
168 /**
169  * Signal SIGUSR2 caught (switch to online mode)
170  * @param param Parameter from the signal interface.
171  */
172 void sigusr2_func(int param)
173 {
174     caught_sig_usr2 = true;
175 } /*lint !e715 */
176
177
178 /**
179  * Signal SIGRTMIN caught (switch to online mode with webcheck enabled)
180  * @param param Parameter from the signal interface.
181  */
182 void sigrtmin_func(int param)
183 {
184     caught_sig_rtmin = true;
185 } /*lint !e715 */
186
187
188 /**
189  * Signal SIGRTMAX caught (increase log level)
190  * @param param Parameter from the signal interface.
191  */
192 void sigrtmax_func(int param)
193 {
194     caught_sig_rtmax = true;
195 } /*lint !e715 */
196
197
198 /**
199  * Initialize the signals we handle.
200  * @return 0 if all is fine, -1 on error.
201  */
202 int init_signals()
203 {
204     sighandler_t ret_val;
205     ret_val = signal(SIGTERM, sigterm_func);
206     if ( ret_val == SIG_ERR )
207     {
208         updater->get_logger()->print_error_setting_signal("SIGTERM");
209         return -1;
210     }
211     ret_val = signal(SIGUSR1, sigusr1_func);
212     if ( ret_val == SIG_ERR )
213     {
214         updater->get_logger()->print_error_setting_signal("SIGUSR1");
215         return -1;
216     }
217     ret_val = signal(SIGHUP, sighup_func);
218     if ( ret_val == SIG_ERR )
219     {
220         updater->get_logger()->print_error_setting_signal("SIGHUP");
221         return -1;
222     }
223     ret_val = signal(SIGUSR2, sigusr2_func);
224     if ( ret_val == SIG_ERR )
225     {
226         updater->get_logger()->print_error_setting_signal("SIGUSR2");
227         return -1;
228     }
229     ret_val = signal(SIGRTMIN, sigrtmin_func);
230     if ( ret_val == SIG_ERR )
231     {
232         updater->get_logger()->print_error_setting_signal("SIGRTMIN");
233         return -1;
234     }
235     ret_val = signal(SIGRTMAX, sigrtmax_func);
236     if ( ret_val == SIG_ERR )
237     {
238         updater->get_logger()->print_error_setting_signal("SIGRTMAX");
239         return -1;
240     }
241
242     return 0;
243 }
244
245
246 /**
247  * Try to run in daemon mode if enabled in config.
248  * @param daemon_mode True if process should detach to init (run as daemon), false if not detach to init.
249  * @return 0 if all is fine, -1 on error.
250  */
251 int init_daemon_mode(bool daemon_mode)
252 {
253     updater->get_logger()->print_daemon_mode(daemon_mode);
254     if ( daemon_mode == true )
255     {
256         int pid = fork();
257         if ( pid < 0 )
258         {
259             // error fork
260             updater->get_logger()->print_error_fork();
261             return -1;
262         }
263         else if ( pid > 0 )
264         {
265             // parent continues here
266             if ( write_pidfile(pid) != 0 )
267             {
268                 if ( kill(pid,SIGTERM) != 0 )
269                 {
270                     updater->get_logger()->print_error_kill_child(pid);
271                     shutdown_parent(false,-1); /*lint !e534 */
272                 }
273                 else
274                 {
275                     updater->get_logger()->print_child_killed(pid);
276                     shutdown_parent(true,-1); /*lint !e534 */
277                 }
278             }
279             updater->get_logger()->print_runnig_as_daemon(pid);
280             shutdown_parent(false,0); /*lint !e534 */
281         }
282         // child starts here
283     }
284     else
285     {
286         if ( write_pidfile(getpid()) != 0 )
287         {
288             shutdown(); /*lint !e534 */
289             exit(-1);
290         }
291     }
292     return 0;
293 }
294
295 /**
296  * Calculate how long the dialup mode burst period will last (dialup mode only)
297  * @return Timestamp until dialup period lasts or zero if dialup mode is disabled
298 */
299 time_t calc_dialup_mode_burst_period()
300 {
301     if (updater->get_config()->get_dialup_mode() )
302         return time(NULL) + updater->get_config()->get_dialup_burst_period_seconds();
303
304     return 0;
305 }
306
307 /**
308  * @brief The main part.
309  * @param argc Number of arguments
310  * @param argv Command line arguments
311  * @return 0 if all is fine.
312  */
313 int main(int argc, char *argv[])
314 {
315     // initialize Updater
316     updater = Updater::Ptr(new Updater);
317
318     // load config and initialize helper classes
319     if ( updater->load_config(argc,argv) != 0 )
320         return -1;
321
322     // open pidfile and check for running process
323     if ( check_for_running_process() != 0)
324         return -1;
325
326     // init signal handling
327     if ( init_signals() != 0)
328         return -1;
329
330     // init daemon_mode if enabled
331     if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
332         return -1;
333
334     // Should we start in offline mode?
335     bool old_online_state = false;
336     bool is_online = !updater->get_config()->get_start_offline();
337     bool webcheck_enabled = updater->get_config()->get_webcheck_enabled();
338     bool exit_now = false;
339
340     // One shot run if daemon mode is disabled
341     if (updater->get_config()->get_daemon_mode() != 1)
342         exit_now = true;
343
344     // Tell the world we are running
345     updater->get_logger()->print_started();
346
347     int original_log_level = updater->get_logger()->get_loglevel();
348
349     // Dialup mode: Sleep a specified number of seconds between network traffic
350     time_t dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
351     time_t dialup_mode_sleep_until = 0;
352
353     // service processing starts here
354     do
355     {
356         // Signal processing
357         if (caught_sig_usr1)
358         {
359             caught_sig_usr1 = false;
360             updater->get_logger()->print_caught_siguser1();
361
362             // Go offline
363             is_online = false;
364         } else if (caught_sig_usr2)
365         {
366             caught_sig_usr2 = false;
367             updater->get_logger()->print_caught_siguser2();
368
369             // Go online
370             is_online = true;
371             webcheck_enabled = false;
372             dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
373         } else if (caught_sig_rtmin)
374         {
375             caught_sig_rtmin = false;
376             updater->get_logger()->print_caught_sigrtmin();
377
378             // Go online - with webcheck
379             is_online = true;
380             webcheck_enabled = true;
381             dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
382         } else if (caught_sig_rtmax)
383         {
384             caught_sig_rtmax = false;
385
386             // Increase log level
387             int new_loglevel = updater->get_logger()->get_loglevel() + 1;
388             updater->get_logger()->print_caught_sigrtmax(new_loglevel);
389             updater->get_logger()->set_loglevel(new_loglevel);
390         } else if (caught_sig_term)
391         {
392             caught_sig_term = false;
393             updater->get_logger()->print_caught_sigterm();
394
395             exit_now = true;
396         } else if (caught_sig_hup)
397         {
398             caught_sig_hup = false;
399             updater->get_logger()->print_caught_sighup();
400
401             if ( updater->reload_config() != 0 )
402             {
403                 updater->get_logger()->print_conf_reload_failed_exit();
404                 exit(-1);
405             }
406
407             // Reset log level to startup log level in case it got elevated by SIGRTMAX
408             updater->get_logger()->set_loglevel(original_log_level);
409
410             // Reset dialup mode burst period on config reload
411             dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
412         }
413
414         // State handling
415         if ( is_online == true )
416         {
417             // Check if webcheck_enabled differs due to caught singnal then set it in config correspondingly
418             if ( updater->get_config()->get_webcheck_enabled() != webcheck_enabled )    /*lint !e731 */
419                 updater->get_config()->set_webcheck_enabled(webcheck_enabled);
420
421             if (updater->get_config()->get_dialup_mode() == false ||
422                 (time(NULL) > dialup_mode_sleep_until || time(NULL) < dialup_mode_burst_mode_until) )
423             {
424                 // update all configured services
425                 updater->update_services(is_online != old_online_state);
426
427                 // Refresh sleep state (dialup mode only)
428                 dialup_mode_sleep_until = time(NULL) + updater->get_config()->get_dialup_sleep_seconds();
429             } else
430                 updater->get_logger()->print_sleep_dialup_mode(dialup_mode_sleep_until);
431         }
432         else
433         {
434             // We are in offline mode, do nothing, expect printing "offline mode".
435             updater->get_logger()->print_offline_mode();
436         }
437
438         // Keep old online state so we can determine
439         // if we switched from offline to online
440         old_online_state = is_online;
441
442         // Snore, snore... don't hog the cpu if we are in daemon_mode.
443         if ( !exit_now )
444             sleep(10); /*lint !e534 */
445     } while ( !exit_now );
446
447     // Serialize services to save their actual state.
448     if ( shutdown() != 0 )
449         return -1;
450
451     return 0;
452 }