Commit | Line | Data |
---|---|---|
91fcc471 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on 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 | 47 | using namespace std; |
2bf8720f | 48 | using boost::shared_ptr; |
365036be | 49 | using boost::posix_time::time_duration; |
301610ca GMF |
50 | using I2n::Logger::GlobalLogger; |
51 | ||
59733431 CH |
52 | // a map from interval (in seconds) to delay (in seconds) |
53 | typedef std::pair<int, float> IntervalCountPair; | |
54 | typedef std::map<int, float> DelayMap; | |
365036be CH |
55 | typedef shared_ptr<boost::asio::deadline_timer> TimerItem; |
56 | ||
57 | const boost::posix_time::time_duration SIGNAL_CHECK_INTERVAL = boost::posix_time::seconds(1); | |
59733431 | 58 | |
7cb9a340 GMF |
59 | //----------------------------------------------------------------------------- |
60 | // Declarations | |
61 | //----------------------------------------------------------------------------- | |
62 | ||
b588279a CH |
63 | typedef std::pair<bool, ConfigurationItem> GetConfigReturnType; |
64 | GetConfigReturnType get_configuration(int, const char**); | |
7cb9a340 GMF |
65 | LinkStatusItem get_status_notifier(const ConfigurationItem&); |
66 | void init_logger(); | |
5ba17410 | 67 | void set_log_output(const ConfigurationItem &); |
59733431 | 68 | DelayMap calc_pinger_delays(const HostList &hosts); |
0fd358ca | 69 | void init_pingers(const IoServiceItem, const ConfigurationItem&, |
365036be | 70 | const LinkStatusItem&, PingSchedulerList*); |
7cb9a340 GMF |
71 | void start_pingers(const PingSchedulerList&); |
72 | void stop_pingers(const PingSchedulerList&); | |
7cb9a340 | 73 | |
666388ba CH |
74 | void signal_handler_int(int param); |
75 | void signal_handler_term(int param); | |
76 | void signal_handler_usr1(int param); | |
77 | void signal_handler_usr2(int param); | |
365036be | 78 | void signal_checker( const boost::system::error_code &error ); |
666388ba | 79 | void install_signal_handlers( const IoServiceItem io_service, const int config_log_level ); |
365036be CH |
80 | void reset_signal_handlers(); |
81 | ||
82 | // data required for signal handling (SIGINT, SIGTERM, ... ) | |
83 | struct 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 | 118 | GetConfigReturnType 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 | 132 | LinkStatusItem 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 | 152 | void 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 |
161 | void 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 | */ | |
204 | DelayMap 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 | 228 | void 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 |
284 | void 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 | ||
293 | void 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 |
309 | signal_data_struct signal_data; | |
310 | ||
0fd358ca | 311 | |
666388ba CH |
312 | /// registered as signal handler; just sets signal_data.signaled_flag |
313 | void signal_handler_int(int param) | |
365036be | 314 | { |
963e98a2 | 315 | signal_data.signaled_flag_int = 1; |
666388ba CH |
316 | } |
317 | void signal_handler_term(int param) | |
318 | { | |
963e98a2 | 319 | signal_data.signaled_flag_term = 1; |
666388ba CH |
320 | } |
321 | void signal_handler_usr1(int param) | |
322 | { | |
963e98a2 | 323 | signal_data.signaled_flag_usr1 = 1; |
666388ba CH |
324 | } |
325 | void 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 | 332 | void 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 | 393 | void 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 | 426 | void 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 |
449 | int 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 | } |