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