Fix 'occurred' typo
[bpdyndnsd] / src / main.cpp
CommitLineData
b1be615b
BS
1/** @file
2 * @brief The main function.
3 *
4 *
5 *
6 * @copyright Intra2net AG
7 * @license GPLv2
8*/
4545a371
BS
9
10#ifdef HAVE_CONFIG_H
11#include <config.h>
12#endif
13
c47386eb 14#define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid"
388f4ab0 15
4545a371 16#include <iostream>
88a594e8 17#include <fstream>
4545a371
BS
18#include <list>
19#include <string>
4545a371 20#include <boost/foreach.hpp>
88a594e8
BS
21#include <sys/types.h>
22#include <signal.h>
23
4de6a9b8 24#include "updater.hpp"
4545a371 25
4545a371
BS
26using namespace std;
27
88a594e8 28Updater::Ptr updater;
e4ebcadc 29volatile bool caught_sig_hup = false;
a6aac246
TJ
30volatile bool caught_sig_usr1 = false;
31volatile bool caught_sig_usr2 = false;
e4ebcadc 32volatile bool caught_sig_rtmin = false;
3f39b968 33volatile bool caught_sig_rtmax = false;
e4ebcadc 34volatile bool caught_sig_term = false;
a6aac246 35
4545a371 36/**
388f4ab0
BS
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 */
c5675c01 41int check_for_running_process()
388f4ab0
BS
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
c5675c01
BS
65
66/**
67 * Writes the pid into the pidfile.
68 * @param pid The process's pid.
69 */
667c672c 70int write_pidfile(int pid)
388f4ab0
BS
71{
72 ofstream pidfile(PIDFILE);
73 if ( pidfile.is_open() )
74 {
75 pidfile << pid << endl;
76 }
667c672c
BS
77 else
78 {
79 updater->get_logger()->print_error_opening_rw(PIDFILE);
80 return -1;
81 }
388f4ab0 82 pidfile.close();
667c672c 83 return 0;
388f4ab0
BS
84}
85
c5675c01
BS
86
87/**
e304c27b
BS
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/**
e4ebcadc 139 * Signal SIGTERM caught (exit program)
c5675c01
BS
140 * @param param Parameter from the signal interface.
141 */
e4ebcadc 142void sigterm_func(int param)
c5675c01 143{
212c7ac3 144 caught_sig_term = true;
08a5a621 145} /*lint !e715 */
c5675c01
BS
146
147
148/**
e4ebcadc 149 * Signal SIGUSR1 caught (switch to offline mode)
c5675c01
BS
150 * @param param Parameter from the signal interface.
151 */
e4ebcadc 152void sigusr1_func(int param)
c5675c01 153{
a6aac246 154 caught_sig_usr1 = true;
08a5a621 155} /*lint !e715 */
c5675c01
BS
156
157
158/**
3f39b968 159 * Signal SIGHUP caught (reload config and reset log level)
39acb828 160 * @param param Parameter from the signal interface.
c5675c01 161 */
e4ebcadc 162void sighup_func(int param)
c5675c01 163{
e4ebcadc 164 caught_sig_hup = true;
64ff14c3
BS
165} /*lint !e715 */
166
167
168/**
e4ebcadc 169 * Signal SIGUSR2 caught (switch to online mode)
64ff14c3
BS
170 * @param param Parameter from the signal interface.
171 */
e4ebcadc 172void sigusr2_func(int param)
64ff14c3 173{
a6aac246 174 caught_sig_usr2 = true;
64ff14c3
BS
175} /*lint !e715 */
176
177
178/**
e4ebcadc 179 * Signal SIGRTMIN caught (switch to online mode with webcheck enabled)
64ff14c3
BS
180 * @param param Parameter from the signal interface.
181 */
e4ebcadc 182void sigrtmin_func(int param)
64ff14c3 183{
e4ebcadc 184 caught_sig_rtmin = true;
08a5a621 185} /*lint !e715 */
c5675c01
BS
186
187
188/**
3f39b968
TJ
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/**
c5675c01 199 * Initialize the signals we handle.
e0080b78 200 * @return 0 if all is fine, -1 on error.
c5675c01 201 */
8bca3c5d 202int init_signals()
c5675c01 203{
8bca3c5d 204 sighandler_t ret_val;
e4ebcadc 205 ret_val = signal(SIGTERM, sigterm_func);
8bca3c5d 206 if ( ret_val == SIG_ERR )
667c672c
BS
207 {
208 updater->get_logger()->print_error_setting_signal("SIGTERM");
8bca3c5d 209 return -1;
667c672c 210 }
e4ebcadc 211 ret_val = signal(SIGUSR1, sigusr1_func);
8bca3c5d 212 if ( ret_val == SIG_ERR )
667c672c
BS
213 {
214 updater->get_logger()->print_error_setting_signal("SIGUSR1");
8bca3c5d 215 return -1;
667c672c 216 }
e4ebcadc 217 ret_val = signal(SIGHUP, sighup_func);
8bca3c5d 218 if ( ret_val == SIG_ERR )
667c672c
BS
219 {
220 updater->get_logger()->print_error_setting_signal("SIGHUP");
8bca3c5d 221 return -1;
667c672c 222 }
e4ebcadc 223 ret_val = signal(SIGUSR2, sigusr2_func);
64ff14c3
BS
224 if ( ret_val == SIG_ERR )
225 {
226 updater->get_logger()->print_error_setting_signal("SIGUSR2");
227 return -1;
228 }
e4ebcadc 229 ret_val = signal(SIGRTMIN, sigrtmin_func);
64ff14c3
BS
230 if ( ret_val == SIG_ERR )
231 {
232 updater->get_logger()->print_error_setting_signal("SIGRTMIN");
233 return -1;
234 }
3f39b968
TJ
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 }
5ac72dd8
BS
241
242 return 0;
c5675c01
BS
243}
244
245
388f4ab0 246/**
584b9407
BS
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 )
e304c27b 269 {
584b9407 270 updater->get_logger()->print_error_kill_child(pid);
557b6f56 271 shutdown_parent(false,-1); /*lint !e534 */
e304c27b 272 }
584b9407 273 else
e304c27b 274 {
584b9407 275 updater->get_logger()->print_child_killed(pid);
557b6f56 276 shutdown_parent(true,-1); /*lint !e534 */
e304c27b 277 }
584b9407
BS
278 }
279 updater->get_logger()->print_runnig_as_daemon(pid);
557b6f56 280 shutdown_parent(false,0); /*lint !e534 */
584b9407
BS
281 }
282 // child starts here
283 }
e304c27b
BS
284 else
285 {
286 if ( write_pidfile(getpid()) != 0 )
287 {
557b6f56 288 shutdown(); /*lint !e534 */
e304c27b
BS
289 exit(-1);
290 }
291 }
584b9407
BS
292 return 0;
293}
294
295/**
c7a2055a
TJ
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/**
b1be615b
BS
308 * @brief The main part.
309 * @param argc Number of arguments
310 * @param argv Command line arguments
311 * @return 0 if all is fine.
4545a371
BS
312 */
313int main(int argc, char *argv[])
314{
38060291 315 // initialize Updater
c3c84086 316 updater = Updater::Ptr(new Updater);
38060291 317
efbde536
BS
318 // load config and initialize helper classes
319 if ( updater->load_config(argc,argv) != 0 )
667c672c 320 return -1;
4545a371 321
388f4ab0 322 // open pidfile and check for running process
c5675c01 323 if ( check_for_running_process() != 0)
667c672c 324 return -1;
3434b35f 325
c5675c01 326 // init signal handling
8bca3c5d 327 if ( init_signals() != 0)
667c672c 328 return -1;
254bbf53 329
584b9407
BS
330 // init daemon_mode if enabled
331 if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
332 return -1;
388f4ab0 333
dbaf4b42 334 // Should we start in offline mode?
d55e13a6 335 bool old_online_state = false;
a6aac246
TJ
336 bool is_online = !updater->get_config()->get_start_offline();
337 bool webcheck_enabled = updater->get_config()->get_webcheck_enabled();
f829f1f3 338 bool exit_now = false;
dbaf4b42 339
c5a6b1fe
TJ
340 // One shot run if daemon mode is disabled
341 if (updater->get_config()->get_daemon_mode() != 1)
342 exit_now = true;
343
e38d7604
TJ
344 // Tell the world we are running
345 updater->get_logger()->print_started();
346
3f39b968
TJ
347 int original_log_level = updater->get_logger()->get_loglevel();
348
c7a2055a
TJ
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
388f4ab0
BS
353 // service processing starts here
354 do
355 {
a6aac246
TJ
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;
c7a2055a 372 dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
e4ebcadc 373 } else if (caught_sig_rtmin)
a6aac246 374 {
e4ebcadc 375 caught_sig_rtmin = false;
a6aac246
TJ
376 updater->get_logger()->print_caught_sigrtmin();
377
378 // Go online - with webcheck
379 is_online = true;
380 webcheck_enabled = true;
c7a2055a 381 dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
3f39b968
TJ
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);
212c7ac3
TJ
390 } else if (caught_sig_term)
391 {
e4ebcadc 392 caught_sig_term = false;
212c7ac3
TJ
393 updater->get_logger()->print_caught_sigterm();
394
395 exit_now = true;
e4ebcadc
TJ
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 }
3f39b968
TJ
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);
c7a2055a
TJ
409
410 // Reset dialup mode burst period on config reload
411 dialup_mode_burst_mode_until = calc_dialup_mode_burst_period();
a6aac246
TJ
412 }
413
414 // State handling
98dd88bd 415 if ( is_online == true )
c5675c01 416 {
46fffdd6 417 // Check if webcheck_enabled differs due to caught singnal then set it in config correspondingly
43f4565e 418 if ( updater->get_config()->get_webcheck_enabled() != webcheck_enabled ) /*lint !e731 */
46fffdd6
BS
419 updater->get_config()->set_webcheck_enabled(webcheck_enabled);
420
c7a2055a
TJ
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);
c5675c01 431 }
8bca3c5d
BS
432 else
433 {
50d63110 434 // We are in offline mode, do nothing, expect printing "offline mode".
8bca3c5d
BS
435 updater->get_logger()->print_offline_mode();
436 }
388f4ab0 437
d55e13a6
TJ
438 // Keep old online state so we can determine
439 // if we switched from offline to online
440 old_online_state = is_online;
441
a7beeb20 442 // Snore, snore... don't hog the cpu if we are in daemon_mode.
c5a6b1fe 443 if ( !exit_now )
557b6f56 444 sleep(10); /*lint !e534 */
c5a6b1fe 445 } while ( !exit_now );
4545a371 446
50d63110 447 // Serialize services to save their actual state.
e304c27b 448 if ( shutdown() != 0 )
667c672c 449 return -1;
2bc1878a 450
4545a371
BS
451 return 0;
452}