Fix 'occurred' typo
[bpdyndnsd] / src / main.cpp
... / ...
CommitLineData
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
26using namespace std;
27
28Updater::Ptr updater;
29volatile bool caught_sig_hup = false;
30volatile bool caught_sig_usr1 = false;
31volatile bool caught_sig_usr2 = false;
32volatile bool caught_sig_rtmin = false;
33volatile bool caught_sig_rtmax = false;
34volatile 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 */
41int 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 */
70int 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 */
91int 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 */
114int 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 */
142void 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 */
152void 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 */
162void 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 */
172void 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 */
182void 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 */
192void 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 */
202int 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 */
251int 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*/
299time_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 */
313int 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}