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