save float comparison; fixed syntax error
[pingcheck] / src / main.cpp
CommitLineData
91fcc471
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
88714861 20#include <signal.h>
238da857 21#include <stdint.h>
88714861 22
c5e4bfa1 23#include <vector>
a4049623 24#include <iostream>
c5e4bfa1 25
e39cc3da 26#include <boost/asio.hpp>
8739a651 27#include <boost/foreach.hpp>
c1fff16a 28#include <boost/shared_ptr.hpp>
59733431
CH
29#include <boost/math/special_functions/round.hpp>
30#include <boost/numeric/conversion/cast.hpp>
365036be 31#include <boost/date_time/posix_time/posix_time_types.hpp>
e4b14784
CH
32#include <boost/random/linear_congruential.hpp>
33#include <boost/random/uniform_real.hpp>
34#include <boost/random/variate_generator.hpp>
4ea9706c 35
301610ca
GMF
36#include <daemonfunc.hpp>
37#include <logfunc.hpp>
8ef29e4a 38
780b0bca 39#include "boost_assert_handler.h"
9c55ecd3
GMF
40#include "config/configurationreader.h"
41#include "config/host.h"
72e54d1c 42#include "link/linkstatus.h"
3625c0e5 43#include "host/loglevel.h"
3fd74a53 44#include "host/pingprotocol.h"
8f66f529 45#include "host/pingscheduler.h"
41d175b0 46#include "icmp/icmppinger.h" // contains IcmpPacketDistributor
c5b4902d 47#include "dns/dnsmaster.h"
4ea9706c 48
780b0bca 49
ad8eb8ab 50using namespace std;
2bf8720f 51using boost::shared_ptr;
365036be 52using boost::posix_time::time_duration;
301610ca
GMF
53using I2n::Logger::GlobalLogger;
54
59733431
CH
55// a map from interval (in seconds) to delay (in seconds)
56typedef std::pair<int, float> IntervalCountPair;
57typedef std::map<int, float> DelayMap;
365036be
CH
58typedef shared_ptr<boost::asio::deadline_timer> TimerItem;
59
60const boost::posix_time::time_duration SIGNAL_CHECK_INTERVAL = boost::posix_time::seconds(1);
59733431 61
7cb9a340
GMF
62//-----------------------------------------------------------------------------
63// Declarations
64//-----------------------------------------------------------------------------
65
b588279a
CH
66typedef std::pair<bool, ConfigurationItem> GetConfigReturnType;
67GetConfigReturnType get_configuration(int, const char**);
7cb9a340
GMF
68LinkStatusItem get_status_notifier(const ConfigurationItem&);
69void init_logger();
5ba17410 70void set_log_output(const ConfigurationItem &);
59733431 71DelayMap calc_pinger_delays(const HostList &hosts);
a85f210b 72bool init_pingers(const IoServiceItem, const ConfigurationItem&,
365036be 73 const LinkStatusItem&, PingSchedulerList*);
7cb9a340
GMF
74void start_pingers(const PingSchedulerList&);
75void stop_pingers(const PingSchedulerList&);
7cb9a340 76
666388ba
CH
77void signal_handler_int(int param);
78void signal_handler_term(int param);
79void signal_handler_usr1(int param);
80void signal_handler_usr2(int param);
365036be 81void signal_checker( const boost::system::error_code &error );
666388ba 82void install_signal_handlers( const IoServiceItem io_service, const int config_log_level );
365036be
CH
83void reset_signal_handlers();
84
85// data required for signal handling (SIGINT, SIGTERM, ... )
86struct signal_data_struct
87{
963e98a2
CH
88 volatile sig_atomic_t signaled_flag_int;
89 volatile sig_atomic_t signaled_flag_term;
90 volatile sig_atomic_t signaled_flag_usr1;
91 volatile sig_atomic_t signaled_flag_usr2;
365036be
CH
92 IoServiceItem io_service;
93 void (*old_handler_int )(int);
94 void (*old_handler_term)(int);
95 void (*old_handler_usr1)(int);
96 void (*old_handler_usr2)(int);
97 bool stopped;
98 TimerItem check_timer;
99 int config_log_level;
100
101 signal_data_struct():
963e98a2
CH
102 signaled_flag_int( 0 ),
103 signaled_flag_term( 0 ),
104 signaled_flag_usr1( 0 ),
105 signaled_flag_usr2( 0 ),
365036be 106 io_service(),
425d0f07
CH
107 old_handler_int( 0 ),
108 old_handler_term( 0 ),
109 old_handler_usr1( 0 ),
110 old_handler_usr2( 0 ),
365036be
CH
111 stopped( false ),
112 check_timer(),
113 config_log_level( I2n::Logger::LogLevel::Notice )
114 { }
115
116};
7cb9a340
GMF
117//-----------------------------------------------------------------------------
118// Definitions
119//-----------------------------------------------------------------------------
35e8afe0 120
b588279a 121GetConfigReturnType get_configuration(
f2c0a5db 122 int argc,
5c3c6449 123 const char *argv[]
f2c0a5db
GMF
124)
125{
f2c0a5db
GMF
126 ConfigurationReader config_reader;
127 bool parsed_success = config_reader.parse( argc, argv );
b588279a 128 Configuration config_obj = config_reader.get_configuration();
f2c0a5db 129
b588279a
CH
130 ConfigurationItem configuration( new Configuration( config_obj ) );
131 GetConfigReturnType return_val( parsed_success, configuration );
132 return return_val;
f2c0a5db
GMF
133}
134
72e54d1c 135LinkStatusItem get_status_notifier(
f2c0a5db
GMF
136 const ConfigurationItem &configuration
137)
138{
139 int hosts_down_limit = configuration->get_hosts_down_limit();
140 int link_up_interval_in_min = configuration->get_link_up_interval_in_min();
1634f2a1 141 int link_down_interval_in_min = configuration->get_link_down_interval_in_min();
f2c0a5db 142 string status_notifier_cmd = configuration->get_status_notifier_cmd();
72e54d1c
GMF
143 LinkStatusItem link_analyzer(
144 new LinkStatus(
f2c0a5db
GMF
145 hosts_down_limit,
146 link_up_interval_in_min,
1634f2a1 147 link_down_interval_in_min,
f2c0a5db
GMF
148 status_notifier_cmd
149 )
150 );
151
152 return link_analyzer;
153}
154
88714861 155void init_logger()
301610ca 156{
0fd358ca
CH
157 // set default: log at level NOTICE to syslog and stderr
158 // to ensure that in case of faulty config, the error is noticed
365036be
CH
159 I2n::Logger::enable_syslog( I2n::Logger::Facility::User );
160 I2n::Logger::enable_stderr_log( true );
0fd358ca 161 I2n::Logger::set_log_level( I2n::Logger::LogLevel::Notice );
88714861
GMF
162}
163
5ba17410
GMF
164void set_log_output(
165 const ConfigurationItem &configuration
166)
167{
168 LogOutput log_output = configuration->get_log_output();
fda777ea 169 string log_file_name = configuration->get_log_file();
5ba17410
GMF
170 switch (log_output)
171 {
a85f210b
CH
172 case LogOutput_UNDEFINED:
173 GlobalLogger.warning() << "Unknown output target -- use syslog";
5ba17410 174 case LogOutput_SYSLOG:
ea16eb5e 175 GlobalLogger.info() << "Setting log output target to syslog" << endl;
5ba17410
GMF
176 I2n::Logger::enable_syslog(true);
177 I2n::Logger::enable_stderr_log(false);
178 I2n::Logger::enable_log_file(false);
ea16eb5e 179 GlobalLogger.info() << "Set log output target to syslog" << endl;
5ba17410
GMF
180 break;
181 case LogOutput_TERMINAL:
ea16eb5e 182 GlobalLogger.info() << "Setting log output target to terminal" << endl;
5ba17410
GMF
183 I2n::Logger::enable_syslog(false);
184 I2n::Logger::enable_stderr_log(true);
185 I2n::Logger::enable_log_file(false);
ea16eb5e
CH
186 GlobalLogger.info() << "Set log output target to terminal" << endl;
187 GlobalLogger.info() << "(check syslog for earlier messages)" << endl;
188 break;
fda777ea
CH
189 case LogOutput_FILE:
190 GlobalLogger.info() << "Setting log output target to file "
191 << log_file_name << endl;
192 I2n::Logger::enable_syslog(false);
193 I2n::Logger::enable_stderr_log(false);
194 I2n::Logger::enable_log_file(log_file_name);
195 GlobalLogger.info() << "Set log output target to file "
196 << log_file_name << endl;
197 GlobalLogger.info() << "(check syslog for earlier messages)" << endl;
198 break;
ea16eb5e
CH
199 default:
200 GlobalLogger.error() << "Unknown log output target!" << endl;
5ba17410
GMF
201 break;
202 }
203}
204
59733431
CH
205/**
206 * @brief calculate delay between pingers to evenly distribute them in time
207 *
208 * If there are many pingers with same interval, will get bursts of pings
209 * and none in-between. This function calculates delays for large numbers
0fd358ca 210 * of hosts with same ping intervals, to distribute them as evenly as
59733431
CH
211 * possible, right from the start (might diverge over time, anyway).
212 *
e4b14784
CH
213 * If interval is chosen at random, will have many pingers with different
214 * intervals; to those will assign a random delay in [0, interval].
59733431
CH
215 *
216 * Called by init_pingers with
217 * @param hosts list of hosts as obtained from configuration
218 * @returns a map from ping interval to delay between pingers of that interval
219 */
220DelayMap calc_pinger_delays(const HostList &hosts)
221{
222 // first step: count number of hosts with same intervals
223 DelayMap delay_shifts;
224 int curr_interval;
c086c9e6 225 BOOST_FOREACH( const HostItem &host, hosts )
59733431
CH
226 {
227 curr_interval = host->get_interval_in_sec();
228 if (! curr_interval)
229 delay_shifts[curr_interval] = 1.0f;
230 else
231 delay_shifts[curr_interval] += 1.0f;
232 }
233
e4b14784
CH
234 // create random number generator
235 typedef boost::rand48 rand_gen_type;
236 typedef boost::uniform_real<float> rand_dist_type;
237 typedef boost::variate_generator< rand_gen_type&,
238 rand_dist_type > rand_var_type;
239 rand_gen_type random_number_generator(
240 boost::numeric_cast<unsigned int>(time(0)) );
241
59733431
CH
242 // second step: divide intervals by counts, round to int
243 // --> for 18 pingers with a 30s interval, get 30s/18 = 1.66667
e4b14784 244 // for random intervals, use random delays within intervals
59733431 245 BOOST_FOREACH( IntervalCountPair interval_and_count, delay_shifts )
e4b14784 246 {
e25e38b8 247 if ( abs(interval_and_count.second - 1.0f) < 0.0001 ) // == 1.0f
e4b14784
CH
248 { // there is exactly 1 pinger with exactly that interval
249 // --> assign a random delay within interval
e25e38b8 250 rand_dist_type random_distribution(0.0f, interval_and_count.first);
e4b14784
CH
251 rand_var_type random_variate(random_number_generator,
252 random_distribution);
253 delay_shifts[interval_and_count.first] = random_variate();
254 }
255 else
256 { // there are several pingers with same interval
257 // --> distribute evenly
258 delay_shifts[interval_and_count.first] =
259 boost::numeric_cast<float>(interval_and_count.first) /
e25e38b8 260 std::max(1.0f, interval_and_count.second); //max is paranoid
e4b14784
CH
261 }
262 }
59733431
CH
263
264 return delay_shifts;
265}
266
a85f210b 267bool init_pingers(
365036be 268 const IoServiceItem io_service,
f2c0a5db 269 const ConfigurationItem &configuration,
72e54d1c 270 const LinkStatusItem &status_notifier,
f2c0a5db
GMF
271 PingSchedulerList *scheduler_list
272)
2666d1f7 273{
035c2305 274 string default_network_interface = configuration->get_source_network_interface();
f2c0a5db 275 int ping_fail_limit = configuration->get_ping_fail_limit();
079d19ab 276 int ping_reply_timeout = configuration->get_ping_reply_timeout();
301610ca 277
096b06ef
CH
278 // remove some hosts at random
279 configuration->randomize_hosts();
280
59733431
CH
281 // calculate delays between pingers of same interval
282 DelayMap delay_shifts = calc_pinger_delays(configuration->get_hosts());
283
e4b14784 284 // setup memory for assigned delays; init with delay > 0
59733431
CH
285 DelayMap delays;
286 BOOST_FOREACH( IntervalCountPair interval_and_delay, delay_shifts )
287 delays[interval_and_delay.first] = 0.0f;
288
f2c0a5db 289 HostList hosts = configuration->get_hosts();
a85f210b
CH
290
291 if (hosts.empty())
292 return false;
293
941b5e25
CH
294 // more variables for pingcheck, maybe should move to config?
295 int n_parallel_pings = 1;
296 int parallel_ping_delay = 100; // ms
297 int congestion_duration_thresh = 10; // seconds
298 int congestion_percentage_thresh = 75;
299 int congest_caused_by_fail_limit_percentage = 99;
300 int ping_timeout_factor = 5;
301
e01cc130 302 BOOST_FOREACH( const HostItem &host, hosts )
2666d1f7 303 {
f2c0a5db 304 string destination_address = host->get_address();
238da857 305 uint16_t destination_port = host->get_port();
035c2305 306 string host_network_interface = host->get_source_network_interface();
27c5a2be
GMF
307 string network_interface = ( host_network_interface == "default" ) ?
308 default_network_interface :
309 host_network_interface;
086e2cc0 310 PingProtocolList protocol_list = host->get_ping_protocol_list();
f2c0a5db 311 int ping_interval_in_sec = host->get_interval_in_sec();
59733431
CH
312
313 // get delay for this scheduler and update assigned delays
59733431 314 delays[ping_interval_in_sec] += delay_shifts[ping_interval_in_sec];
e4b14784
CH
315 int current_delay = boost::math::iround(delays[ping_interval_in_sec]);
316 GlobalLogger.notice() << "TEST: assigning delay of " << current_delay
317 << "s to pinger with interval " << ping_interval_in_sec << "s";
59733431 318
f2c0a5db
GMF
319 PingSchedulerItem scheduler(
320 new PingScheduler(
fc7ae593 321 io_service,
035c2305 322 network_interface,
f2c0a5db 323 destination_address,
1309d0e4 324 destination_port,
086e2cc0 325 protocol_list,
f2c0a5db
GMF
326 ping_interval_in_sec,
327 ping_fail_limit,
a7b15639 328 congestion_percentage_thresh,
941b5e25 329 congest_caused_by_fail_limit_percentage,
a7b15639 330 congestion_duration_thresh,
079d19ab 331 ping_reply_timeout,
59733431 332 status_notifier,
91aa83f9
CH
333 current_delay,
334 n_parallel_pings,
87758553
CH
335 parallel_ping_delay,
336 ping_timeout_factor
f1bf3249 337 )
c1fff16a 338 );
f2c0a5db
GMF
339 scheduler_list->push_back( scheduler );
340 }
a85f210b
CH
341
342 return true;
f2c0a5db 343}
c1fff16a 344
f2c0a5db
GMF
345void start_pingers(
346 const PingSchedulerList &scheduler_list
347)
348{
88714861 349 // start each ping scheduler
e01cc130 350 BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list )
365036be 351 scheduler->start_pinging();
88714861
GMF
352}
353
354void stop_pingers(
355 const PingSchedulerList &scheduler_list
356)
357{
1d1ae364
TJ
358 // Stop each ping scheduler
359 GlobalLogger.info() << "Telling all pingers to stop";
e01cc130 360 BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list )
88714861 361 {
365036be 362 scheduler->stop_pinging();
88714861 363 }
0470811e 364
1ece191b 365 IcmpPacketDistributor::clean_up_all();
88714861
GMF
366}
367
35e8afe0 368
365036be
CH
369// the one instance of signal_data_struct
370signal_data_struct signal_data;
371
0fd358ca 372
666388ba
CH
373/// registered as signal handler; just sets signal_data.signaled_flag
374void signal_handler_int(int param)
365036be 375{
963e98a2 376 signal_data.signaled_flag_int = 1;
666388ba
CH
377}
378void signal_handler_term(int param)
379{
963e98a2 380 signal_data.signaled_flag_term = 1;
666388ba
CH
381}
382void signal_handler_usr1(int param)
383{
963e98a2 384 signal_data.signaled_flag_usr1 = 1;
666388ba
CH
385}
386void signal_handler_usr2(int param)
387{
963e98a2 388 signal_data.signaled_flag_usr2 = 1;
35e8afe0
TJ
389}
390
0fd358ca
CH
391
392/// called regularly from io_service; checks signal_data.signal_flag
365036be 393void signal_checker( const boost::system::error_code &error )
35e8afe0 394{
365036be 395 bool want_stop = false;
35e8afe0 396
365036be
CH
397 if ( error )
398 { // there was an error in the timer
399 if ( error == boost::asio::error::operation_aborted )
35e8afe0 400 {
365036be
CH
401 GlobalLogger.error() << "Signal check timer was cancelled! Stopping io_service" << endl;
402 want_stop = true;
0b920e26
GMF
403 }
404 else
405 {
0fd358ca
CH
406 GlobalLogger.error() << "Signal check timer handler received error code " << error
407 << "! Stopping io_service" << endl;
365036be 408 want_stop = true;
0b920e26 409 }
35e8afe0 410 }
716deecb
CH
411 else {
412 if ( signal_data.signaled_flag_int )
413 {
963e98a2 414 signal_data.signaled_flag_int = 0;
716deecb
CH
415 GlobalLogger.notice() << "Received signal SIGINT --> will stop" << endl;
416 want_stop = true;
417 }
418 else if ( signal_data.signaled_flag_term )
419 {
963e98a2 420 signal_data.signaled_flag_term = 0;
716deecb
CH
421 GlobalLogger.notice() << "Received signal SIGTERM --> will stop" << endl;
422 want_stop = true;
423 }
424 else if ( signal_data.signaled_flag_usr1 )
365036be 425 {
963e98a2 426 signal_data.signaled_flag_usr1 = 0;
365036be
CH
427 int new_log_level = I2n::Logger::get_log_level()+1;
428 I2n::Logger::set_log_level( new_log_level );
666388ba 429 GlobalLogger.info() << "Received SIGUSR1 -- increased log level to "
365036be
CH
430 << I2n::Logger::get_log_level_string();
431 }
716deecb 432 else if ( signal_data.signaled_flag_usr2 )
365036be 433 {
963e98a2 434 signal_data.signaled_flag_usr2 = 0;
365036be 435 I2n::Logger::set_log_level( signal_data.config_log_level );
666388ba 436 GlobalLogger.info() << "Received SIGUSR2 -- reset log level to normal ("
365036be
CH
437 << I2n::Logger::get_log_level_string() << ")";
438 }
365036be 439 }
fc7ae593 440
365036be
CH
441 if ( want_stop )
442 { // interrupt infinite loop in main and asio event loop
443 signal_data.stopped = true;
444 signal_data.io_service->stop();
fc7ae593
CH
445 }
446 else
365036be 447 { // re-schedule timer
365036be
CH
448 signal_data.check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL );
449 signal_data.check_timer->async_wait( signal_checker );
fc7ae593
CH
450 }
451}
452
365036be 453/// register own signal handlers; see reset_signal_handlers for undo
666388ba 454void install_signal_handlers( const IoServiceItem io_service, const int config_log_level )
fc7ae593 455{
963e98a2
CH
456 signal_data.signaled_flag_int = 0;
457 signal_data.signaled_flag_term = 0;
458 signal_data.signaled_flag_usr1 = 0;
459 signal_data.signaled_flag_usr2 = 0;
365036be 460 signal_data.config_log_level = config_log_level;
fc7ae593
CH
461
462 // install own signal handlers
666388ba
CH
463 signal_data.old_handler_int = signal(SIGINT, signal_handler_int);
464 signal_data.old_handler_term = signal(SIGTERM, signal_handler_term);
465 signal_data.old_handler_usr1 = signal(SIGUSR1, signal_handler_usr1);
466 signal_data.old_handler_usr2 = signal(SIGUSR2, signal_handler_usr2);
fc7ae593
CH
467 if ( signal_data.old_handler_int == SIG_ERR ||
468 signal_data.old_handler_term == SIG_ERR ||
469 signal_data.old_handler_usr1 == SIG_ERR ||
470 signal_data.old_handler_usr2 == SIG_ERR )
365036be
CH
471 throw runtime_error( string("Failed to install signal handler: ") + string(strerror(errno)) );
472
473 // create a timer and a shared pointer to it, so it does not get out of scope
474 TimerItem check_timer( new boost::asio::deadline_timer( *io_service ) );
fc7ae593 475
365036be 476 // remember the io_service and the timer
fc7ae593 477 signal_data.io_service = io_service;
365036be 478 signal_data.check_timer = check_timer;
fc7ae593 479
365036be
CH
480 // set the timer
481 check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL );
482 check_timer->async_wait( signal_checker );
483 GlobalLogger.debug() << "signal timer set" << endl;
fc7ae593
CH
484}
485
666388ba 486/// reset handlers to the ones saved in install_signal_handlers
365036be 487void reset_signal_handlers()
f2c0a5db 488{
425d0f07
CH
489 void (*old_handler_int)(int) = 0;
490 void (*old_handler_term)(int) = 0;
491 void (*old_handler_usr1)(int) = 0;
492 void (*old_handler_usr2)(int) = 0;
493 if (signal_data.old_handler_int != 0 )
494 old_handler_int = signal(SIGINT , signal_data.old_handler_int);
495 if (signal_data.old_handler_term != 0 )
496 old_handler_term = signal(SIGTERM, signal_data.old_handler_term);
497 if (signal_data.old_handler_usr1 != 0 )
498 old_handler_usr1 = signal(SIGUSR1, signal_data.old_handler_usr1);
499 if (signal_data.old_handler_usr2 != 0 )
500 old_handler_usr2 = signal(SIGUSR2, signal_data.old_handler_usr2);
365036be
CH
501
502 if ( old_handler_int == SIG_ERR ||
503 old_handler_term == SIG_ERR ||
504 old_handler_usr1 == SIG_ERR ||
505 old_handler_usr2 == SIG_ERR )
506 throw runtime_error( string("Failed to reset signal handler: ") + string(strerror(errno)) );
507}
508
35e8afe0 509
365036be
CH
510int main( int argc, const char *argv[] )
511{
88714861 512 init_logger();
99ee8244 513 GlobalLogger.debug() << "logger initiated with default config";
f2c0a5db 514
6e8c880d 515 PingSchedulerList scheduler_list;
365036be 516 IoServiceItem io_service;
6e8c880d 517 int ret_code = 0;
ad83004d 518
6e8c880d 519 try
f2c0a5db 520 {
b588279a
CH
521 GetConfigReturnType success_and_config = get_configuration( argc, argv );
522 ConfigurationItem configuration = success_and_config.second;
523
524 if ( configuration->get_print_version() ) // do this even if parsing of config failed
525 {
a85f210b
CH
526 GlobalLogger.debug() << "Printing version info ("
527 << VERSION_STRING << "." << VERSION_REVISION_STRING
528 << " build " << __DATE__
529 << ") and exit" << endl;
530 cout << PROJECT_NAME << " version "
531 << VERSION_STRING << "." << VERSION_REVISION_STRING
532 << " build " << __DATE__
533 << endl;
b588279a
CH
534 return 0;
535 }
536
537 if ( ! success_and_config.first )
6e8c880d 538 {
b588279a
CH
539 GlobalLogger.error() << "Could not read/parse configuration!";
540 GlobalLogger.debug() << "Return 1 immediately" << endl;
fc7ae593
CH
541 return 1;
542 }
b588279a 543 GlobalLogger.debug() << "Start setup" << endl;
1d1ae364 544
fc7ae593 545 int log_level = configuration->get_log_level();
365036be 546 I2n::Logger::set_log_level( log_level );
fc7ae593 547 GlobalLogger.info() << "Set LogLevel to " << I2n::Logger::get_log_level_string() << endl;
5ba17410 548
fc7ae593 549 set_log_output( configuration );
a85f210b
CH
550 GlobalLogger.notice() << "started pingcheck version "
551 << VERSION_STRING << "." << VERSION_REVISION_STRING
552 << " build " << __DATE__
553 << endl;
f2c0a5db 554
fc7ae593
CH
555 bool daemon_mode = configuration->get_daemon();
556 if ( daemon_mode )
557 {
558 I2n::Daemon::daemonize();
559 }
f2c0a5db 560
fc7ae593 561 LinkStatusItem status_notifier = get_status_notifier( configuration );
f2c0a5db 562
365036be
CH
563 IoServiceItem io_service_temp( new boost::asio::io_service() );
564 io_service_temp.swap( io_service );
565 io_service_temp.reset();
fc7ae593 566
9490a7bd
CH
567 // create Dns master
568 boost::asio::ip::address name_server_ip =
569 boost::asio::ip::address::from_string(
570 configuration->get_nameserver() );
a85f210b 571 int max_recursion_count = 10; // could make a config var some time
9490a7bd
CH
572 DnsMaster::create_master(
573 io_service,
574 name_server_ip,
575 configuration->get_resolved_ip_ttl_threshold(),
f833126b 576 configuration->get_min_time_between_resolves(),
9490a7bd 577 configuration->get_max_address_resolution_attempts(),
cd71d095 578 max_recursion_count,
9490a7bd
CH
579 configuration->get_dns_cache_file() );
580
a85f210b
CH
581 if ( !init_pingers(io_service, configuration, status_notifier,
582 &scheduler_list) )
583 {
584 GlobalLogger.error() << "Could not initialize pingers or no hosts "
585 << "given to ping --> exit";
586 return 2;
587 }
fc7ae593 588
666388ba 589 install_signal_handlers( io_service, log_level );
88714861 590
365036be 591 start_pingers( scheduler_list );
6e8c880d 592 }
aaff53da 593 catch ( const std::exception &ex )
6e8c880d 594 {
fc7ae593 595 GlobalLogger.error() << "Uncaught exception. " << ex.what() << endl;
a85f210b 596 ret_code = 3;
6e8c880d
CH
597 }
598 catch (...) {
fc7ae593 599 GlobalLogger.error() << "Caught unknown exception!" << endl;
a85f210b 600 ret_code = 4;
6e8c880d 601 }
35e8afe0 602
365036be 603 if ( ret_code == 0 )
fc7ae593 604 {
747c13ca 605 GlobalLogger.info() << "starting io_service main loop" << endl;
ad83004d 606
365036be 607 // call boost::asio main event loop, catching exceptions
7840efba
CH
608 try
609 {
610 io_service->run();
611 }
612 catch ( const std::exception &ex )
fc7ae593 613 {
7840efba
CH
614 GlobalLogger.error() << "Caught exception, will continue. " << ex.what() << endl;
615 }
616 catch (...) {
617 GlobalLogger.error() << "Caught unknown exception, will continue!" << endl;
fc7ae593
CH
618 }
619 }
620
6e8c880d
CH
621 // clean up
622 try
623 {
624 GlobalLogger.info() << "Cleaning up" << endl;
1d1ae364 625 stop_pingers( scheduler_list );
365036be 626 reset_signal_handlers();
ced28dc7 627 }
aaff53da 628 catch ( const std::exception &ex )
6e8c880d 629 {
fc7ae593 630 GlobalLogger.error() << "Uncaught exception while cleaning up: " << ex.what() << endl;
a85f210b 631 ret_code += 16;
6e8c880d
CH
632 }
633 catch (...) {
fc7ae593 634 GlobalLogger.error() << "Caught unknown exception while cleaning up!" << endl;
a85f210b 635 ret_code += 32;
6e8c880d 636 }
4ea9706c 637
365036be 638 GlobalLogger.notice() << "Pingcheck done " << endl;
6e8c880d 639 return ret_code;
4ea9706c 640}