merged PingRotate into PingScheduler; fixed save/load of cache to/from file; started...
[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();
166 switch (log_output)
167 {
168 case LogOutput_SYSLOG:
ea16eb5e 169 GlobalLogger.info() << "Setting log output target to syslog" << endl;
5ba17410
GMF
170 I2n::Logger::enable_syslog(true);
171 I2n::Logger::enable_stderr_log(false);
172 I2n::Logger::enable_log_file(false);
ea16eb5e 173 GlobalLogger.info() << "Set log output target to syslog" << endl;
5ba17410
GMF
174 break;
175 case LogOutput_TERMINAL:
ea16eb5e 176 GlobalLogger.info() << "Setting log output target to terminal" << endl;
5ba17410
GMF
177 I2n::Logger::enable_syslog(false);
178 I2n::Logger::enable_stderr_log(true);
179 I2n::Logger::enable_log_file(false);
ea16eb5e
CH
180 GlobalLogger.info() << "Set log output target to terminal" << endl;
181 GlobalLogger.info() << "(check syslog for earlier messages)" << endl;
182 break;
183 default:
184 GlobalLogger.error() << "Unknown log output target!" << endl;
5ba17410
GMF
185 break;
186 }
187}
188
59733431
CH
189/**
190 * @brief calculate delay between pingers to evenly distribute them in time
191 *
192 * If there are many pingers with same interval, will get bursts of pings
193 * and none in-between. This function calculates delays for large numbers
0fd358ca 194 * of hosts with same ping intervals, to distribute them as evenly as
59733431
CH
195 * possible, right from the start (might diverge over time, anyway).
196 *
197 * Will not do much good for pingers with many different intervals, but
198 * then is not required anyway and does no(t much) harm.
199 *
200 * Called by init_pingers with
201 * @param hosts list of hosts as obtained from configuration
202 * @returns a map from ping interval to delay between pingers of that interval
203 */
204DelayMap calc_pinger_delays(const HostList &hosts)
205{
206 // first step: count number of hosts with same intervals
207 DelayMap delay_shifts;
208 int curr_interval;
c086c9e6 209 BOOST_FOREACH( const HostItem &host, hosts )
59733431
CH
210 {
211 curr_interval = host->get_interval_in_sec();
212 if (! curr_interval)
213 delay_shifts[curr_interval] = 1.0f;
214 else
215 delay_shifts[curr_interval] += 1.0f;
216 }
217
218 // second step: divide intervals by counts, round to int
219 // --> for 18 pingers with a 30s interval, get 30s/18 = 1.66667
220 BOOST_FOREACH( IntervalCountPair interval_and_count, delay_shifts )
221 delay_shifts[interval_and_count.first] =
222 boost::numeric_cast<float>(interval_and_count.first) /
223 interval_and_count.second;
224
225 return delay_shifts;
226}
227
f2c0a5db 228void init_pingers(
365036be 229 const IoServiceItem io_service,
f2c0a5db 230 const ConfigurationItem &configuration,
72e54d1c 231 const LinkStatusItem &status_notifier,
f2c0a5db
GMF
232 PingSchedulerList *scheduler_list
233)
2666d1f7 234{
035c2305 235 string default_network_interface = configuration->get_source_network_interface();
f2c0a5db 236 int ping_fail_limit = configuration->get_ping_fail_limit();
079d19ab 237 int ping_reply_timeout = configuration->get_ping_reply_timeout();
301610ca 238
096b06ef
CH
239 // remove some hosts at random
240 configuration->randomize_hosts();
241
59733431
CH
242 // calculate delays between pingers of same interval
243 DelayMap delay_shifts = calc_pinger_delays(configuration->get_hosts());
244
245 // setup memory for assigned delays
246 DelayMap delays;
247 BOOST_FOREACH( IntervalCountPair interval_and_delay, delay_shifts )
248 delays[interval_and_delay.first] = 0.0f;
249
f2c0a5db 250 HostList hosts = configuration->get_hosts();
e01cc130 251 BOOST_FOREACH( const HostItem &host, hosts )
2666d1f7 252 {
f2c0a5db 253 string destination_address = host->get_address();
238da857 254 uint16_t destination_port = host->get_port();
035c2305 255 string host_network_interface = host->get_source_network_interface();
27c5a2be
GMF
256 string network_interface = ( host_network_interface == "default" ) ?
257 default_network_interface :
258 host_network_interface;
086e2cc0 259 PingProtocolList protocol_list = host->get_ping_protocol_list();
f2c0a5db 260 int ping_interval_in_sec = host->get_interval_in_sec();
59733431
CH
261
262 // get delay for this scheduler and update assigned delays
263 int current_delay = boost::math::iround(delays[ping_interval_in_sec]);
264 delays[ping_interval_in_sec] += delay_shifts[ping_interval_in_sec];
265
f2c0a5db
GMF
266 PingSchedulerItem scheduler(
267 new PingScheduler(
fc7ae593 268 io_service,
035c2305 269 network_interface,
f2c0a5db 270 destination_address,
1309d0e4 271 destination_port,
086e2cc0 272 protocol_list,
f2c0a5db
GMF
273 ping_interval_in_sec,
274 ping_fail_limit,
079d19ab 275 ping_reply_timeout,
59733431
CH
276 status_notifier,
277 current_delay
f1bf3249 278 )
c1fff16a 279 );
f2c0a5db
GMF
280 scheduler_list->push_back( scheduler );
281 }
282}
c1fff16a 283
f2c0a5db
GMF
284void start_pingers(
285 const PingSchedulerList &scheduler_list
286)
287{
88714861 288 // start each ping scheduler
e01cc130 289 BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list )
365036be 290 scheduler->start_pinging();
88714861
GMF
291}
292
293void stop_pingers(
294 const PingSchedulerList &scheduler_list
295)
296{
1d1ae364
TJ
297 // Stop each ping scheduler
298 GlobalLogger.info() << "Telling all pingers to stop";
e01cc130 299 BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list )
88714861 300 {
365036be 301 scheduler->stop_pinging();
88714861 302 }
0470811e 303
1ece191b 304 IcmpPacketDistributor::clean_up_all();
88714861
GMF
305}
306
35e8afe0 307
365036be
CH
308// the one instance of signal_data_struct
309signal_data_struct signal_data;
310
0fd358ca 311
666388ba
CH
312/// registered as signal handler; just sets signal_data.signaled_flag
313void signal_handler_int(int param)
365036be 314{
963e98a2 315 signal_data.signaled_flag_int = 1;
666388ba
CH
316}
317void signal_handler_term(int param)
318{
963e98a2 319 signal_data.signaled_flag_term = 1;
666388ba
CH
320}
321void signal_handler_usr1(int param)
322{
963e98a2 323 signal_data.signaled_flag_usr1 = 1;
666388ba
CH
324}
325void signal_handler_usr2(int param)
326{
963e98a2 327 signal_data.signaled_flag_usr2 = 1;
35e8afe0
TJ
328}
329
0fd358ca
CH
330
331/// called regularly from io_service; checks signal_data.signal_flag
365036be 332void signal_checker( const boost::system::error_code &error )
35e8afe0 333{
365036be 334 bool want_stop = false;
35e8afe0 335
365036be
CH
336 if ( error )
337 { // there was an error in the timer
338 if ( error == boost::asio::error::operation_aborted )
35e8afe0 339 {
365036be
CH
340 GlobalLogger.error() << "Signal check timer was cancelled! Stopping io_service" << endl;
341 want_stop = true;
0b920e26
GMF
342 }
343 else
344 {
0fd358ca
CH
345 GlobalLogger.error() << "Signal check timer handler received error code " << error
346 << "! Stopping io_service" << endl;
365036be 347 want_stop = true;
0b920e26 348 }
35e8afe0 349 }
716deecb
CH
350 else {
351 if ( signal_data.signaled_flag_int )
352 {
963e98a2 353 signal_data.signaled_flag_int = 0;
716deecb
CH
354 GlobalLogger.notice() << "Received signal SIGINT --> will stop" << endl;
355 want_stop = true;
356 }
357 else if ( signal_data.signaled_flag_term )
358 {
963e98a2 359 signal_data.signaled_flag_term = 0;
716deecb
CH
360 GlobalLogger.notice() << "Received signal SIGTERM --> will stop" << endl;
361 want_stop = true;
362 }
363 else if ( signal_data.signaled_flag_usr1 )
365036be 364 {
963e98a2 365 signal_data.signaled_flag_usr1 = 0;
365036be
CH
366 int new_log_level = I2n::Logger::get_log_level()+1;
367 I2n::Logger::set_log_level( new_log_level );
666388ba 368 GlobalLogger.info() << "Received SIGUSR1 -- increased log level to "
365036be
CH
369 << I2n::Logger::get_log_level_string();
370 }
716deecb 371 else if ( signal_data.signaled_flag_usr2 )
365036be 372 {
963e98a2 373 signal_data.signaled_flag_usr2 = 0;
365036be 374 I2n::Logger::set_log_level( signal_data.config_log_level );
666388ba 375 GlobalLogger.info() << "Received SIGUSR2 -- reset log level to normal ("
365036be
CH
376 << I2n::Logger::get_log_level_string() << ")";
377 }
365036be 378 }
fc7ae593 379
365036be
CH
380 if ( want_stop )
381 { // interrupt infinite loop in main and asio event loop
382 signal_data.stopped = true;
383 signal_data.io_service->stop();
fc7ae593
CH
384 }
385 else
365036be 386 { // re-schedule timer
365036be
CH
387 signal_data.check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL );
388 signal_data.check_timer->async_wait( signal_checker );
fc7ae593
CH
389 }
390}
391
365036be 392/// register own signal handlers; see reset_signal_handlers for undo
666388ba 393void install_signal_handlers( const IoServiceItem io_service, const int config_log_level )
fc7ae593 394{
963e98a2
CH
395 signal_data.signaled_flag_int = 0;
396 signal_data.signaled_flag_term = 0;
397 signal_data.signaled_flag_usr1 = 0;
398 signal_data.signaled_flag_usr2 = 0;
365036be 399 signal_data.config_log_level = config_log_level;
fc7ae593
CH
400
401 // install own signal handlers
666388ba
CH
402 signal_data.old_handler_int = signal(SIGINT, signal_handler_int);
403 signal_data.old_handler_term = signal(SIGTERM, signal_handler_term);
404 signal_data.old_handler_usr1 = signal(SIGUSR1, signal_handler_usr1);
405 signal_data.old_handler_usr2 = signal(SIGUSR2, signal_handler_usr2);
fc7ae593
CH
406 if ( signal_data.old_handler_int == SIG_ERR ||
407 signal_data.old_handler_term == SIG_ERR ||
408 signal_data.old_handler_usr1 == SIG_ERR ||
409 signal_data.old_handler_usr2 == SIG_ERR )
365036be
CH
410 throw runtime_error( string("Failed to install signal handler: ") + string(strerror(errno)) );
411
412 // create a timer and a shared pointer to it, so it does not get out of scope
413 TimerItem check_timer( new boost::asio::deadline_timer( *io_service ) );
fc7ae593 414
365036be 415 // remember the io_service and the timer
fc7ae593 416 signal_data.io_service = io_service;
365036be 417 signal_data.check_timer = check_timer;
fc7ae593 418
365036be
CH
419 // set the timer
420 check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL );
421 check_timer->async_wait( signal_checker );
422 GlobalLogger.debug() << "signal timer set" << endl;
fc7ae593
CH
423}
424
666388ba 425/// reset handlers to the ones saved in install_signal_handlers
365036be 426void reset_signal_handlers()
f2c0a5db 427{
425d0f07
CH
428 void (*old_handler_int)(int) = 0;
429 void (*old_handler_term)(int) = 0;
430 void (*old_handler_usr1)(int) = 0;
431 void (*old_handler_usr2)(int) = 0;
432 if (signal_data.old_handler_int != 0 )
433 old_handler_int = signal(SIGINT , signal_data.old_handler_int);
434 if (signal_data.old_handler_term != 0 )
435 old_handler_term = signal(SIGTERM, signal_data.old_handler_term);
436 if (signal_data.old_handler_usr1 != 0 )
437 old_handler_usr1 = signal(SIGUSR1, signal_data.old_handler_usr1);
438 if (signal_data.old_handler_usr2 != 0 )
439 old_handler_usr2 = signal(SIGUSR2, signal_data.old_handler_usr2);
365036be
CH
440
441 if ( old_handler_int == SIG_ERR ||
442 old_handler_term == SIG_ERR ||
443 old_handler_usr1 == SIG_ERR ||
444 old_handler_usr2 == SIG_ERR )
445 throw runtime_error( string("Failed to reset signal handler: ") + string(strerror(errno)) );
446}
447
35e8afe0 448
365036be
CH
449int main( int argc, const char *argv[] )
450{
88714861 451 init_logger();
99ee8244 452 GlobalLogger.debug() << "logger initiated with default config";
f2c0a5db 453
6e8c880d 454 PingSchedulerList scheduler_list;
365036be 455 IoServiceItem io_service;
6e8c880d 456 int ret_code = 0;
365036be 457 unsigned n_exceptions = 0;
ad83004d
CH
458 unsigned max_exceptions = 1;
459
6e8c880d 460 try
f2c0a5db 461 {
b588279a
CH
462 GetConfigReturnType success_and_config = get_configuration( argc, argv );
463 ConfigurationItem configuration = success_and_config.second;
464
465 if ( configuration->get_print_version() ) // do this even if parsing of config failed
466 {
467 GlobalLogger.debug() << "Printing version info (" << VERSION_STRING << ") and exit" << endl;
402d0469
CH
468 cout << PROJECT_NAME << " version " << VERSION_STRING << "."
469 << VERSION_REVISION_STRING << " build " << __DATE__ << endl;
b588279a
CH
470 return 0;
471 }
472
473 if ( ! success_and_config.first )
6e8c880d 474 {
b588279a
CH
475 GlobalLogger.error() << "Could not read/parse configuration!";
476 GlobalLogger.debug() << "Return 1 immediately" << endl;
fc7ae593
CH
477 return 1;
478 }
b588279a 479 GlobalLogger.debug() << "Start setup" << endl;
1d1ae364 480
fc7ae593 481 int log_level = configuration->get_log_level();
365036be 482 I2n::Logger::set_log_level( log_level );
fc7ae593 483 GlobalLogger.info() << "Set LogLevel to " << I2n::Logger::get_log_level_string() << endl;
5ba17410 484
fc7ae593
CH
485 set_log_output( configuration );
486 GlobalLogger.notice() << "started";
f2c0a5db 487
fc7ae593
CH
488 bool daemon_mode = configuration->get_daemon();
489 if ( daemon_mode )
490 {
491 I2n::Daemon::daemonize();
492 }
f2c0a5db 493
fc7ae593 494 LinkStatusItem status_notifier = get_status_notifier( configuration );
f2c0a5db 495
365036be
CH
496 IoServiceItem io_service_temp( new boost::asio::io_service() );
497 io_service_temp.swap( io_service );
498 io_service_temp.reset();
fc7ae593 499
9490a7bd
CH
500 // create Dns master
501 boost::asio::ip::address name_server_ip =
502 boost::asio::ip::address::from_string(
503 configuration->get_nameserver() );
504
505 DnsMaster::create_master(
506 io_service,
507 name_server_ip,
508 configuration->get_resolved_ip_ttl_threshold(),
509 configuration->get_max_address_resolution_attempts(),
510 configuration->get_dns_cache_file() );
511
fc7ae593
CH
512 init_pingers( io_service, configuration, status_notifier, &scheduler_list );
513
666388ba 514 install_signal_handlers( io_service, log_level );
88714861 515
365036be 516 start_pingers( scheduler_list );
6e8c880d 517 }
aaff53da 518 catch ( const std::exception &ex )
6e8c880d 519 {
fc7ae593 520 GlobalLogger.error() << "Uncaught exception. " << ex.what() << endl;
c34a1f77 521 ret_code = 2;
365036be 522 ++n_exceptions;
6e8c880d
CH
523 }
524 catch (...) {
fc7ae593 525 GlobalLogger.error() << "Caught unknown exception!" << endl;
c34a1f77 526 ret_code = 3;
365036be 527 ++n_exceptions;
6e8c880d 528 }
35e8afe0 529
365036be 530 if ( ret_code == 0 )
fc7ae593 531 {
747c13ca 532 GlobalLogger.info() << "starting io_service main loop" << endl;
ad83004d
CH
533
534 if (max_exceptions > 0)
535 GlobalLogger.warning() << "Limited number of acceptable exceptions,"
536 << " this is a debugging option!";
537
365036be
CH
538 // call boost::asio main event loop, catching exceptions
539 while ( !signal_data.stopped )
fc7ae593 540 {
365036be
CH
541 try
542 {
365036be
CH
543 io_service->run();
544 }
545 catch ( const std::exception &ex )
546 {
547 ++n_exceptions;
548 GlobalLogger.error() << "Caught exception, will continue. " << ex.what() << endl;
549 }
550 catch (...) {
551 ++n_exceptions;
552 GlobalLogger.error() << "Caught unknown exception, will continue!" << endl;
553 }
ce330b20
CH
554
555 if (max_exceptions > 0 && n_exceptions >= max_exceptions)
556 {
557 GlobalLogger.info() << "reached max number of exceptions allowed in main loop" << endl;
558 io_service->stop();
559 signal_data.stopped = true;
560 break;
561 }
e75a59e7
CH
562 else if ( signal_data.stopped )
563 GlobalLogger.info() << "exiting io_service main loop" << endl;
564 // ( io_service->stop() has been called already in signal handler)
565 else
566 GlobalLogger.info() << "continuing io_service main loop" << endl;
fc7ae593
CH
567 }
568 }
569
6e8c880d
CH
570 // clean up
571 try
572 {
573 GlobalLogger.info() << "Cleaning up" << endl;
1d1ae364 574 stop_pingers( scheduler_list );
365036be 575 reset_signal_handlers();
ced28dc7 576 }
aaff53da 577 catch ( const std::exception &ex )
6e8c880d 578 {
fc7ae593 579 GlobalLogger.error() << "Uncaught exception while cleaning up: " << ex.what() << endl;
6e8c880d
CH
580 ret_code += 4;
581 }
582 catch (...) {
fc7ae593 583 GlobalLogger.error() << "Caught unknown exception while cleaning up!" << endl;
6e8c880d
CH
584 ret_code += 8;
585 }
4ea9706c 586
365036be
CH
587 GlobalLogger.notice() << "Pingcheck done " << endl;
588 GlobalLogger.debug() << "In main loop, had " << n_exceptions << " exception[s]" << endl;
6e8c880d 589 return ret_code;
4ea9706c 590}