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]; | |
91aa83f9 CH |
282 | int n_parallel_pings = 10; |
283 | int parallel_ping_delay = 100; // ms | |
a7b15639 CH |
284 | int congestion_duration_thresh = 10; // seconds |
285 | int congestion_percentage_thresh = 75; | |
59733431 | 286 | |
f2c0a5db GMF |
287 | PingSchedulerItem scheduler( |
288 | new PingScheduler( | |
fc7ae593 | 289 | io_service, |
035c2305 | 290 | network_interface, |
f2c0a5db | 291 | destination_address, |
1309d0e4 | 292 | destination_port, |
086e2cc0 | 293 | protocol_list, |
f2c0a5db GMF |
294 | ping_interval_in_sec, |
295 | ping_fail_limit, | |
a7b15639 CH |
296 | congestion_percentage_thresh, |
297 | congestion_duration_thresh, | |
079d19ab | 298 | ping_reply_timeout, |
59733431 | 299 | status_notifier, |
91aa83f9 CH |
300 | current_delay, |
301 | n_parallel_pings, | |
302 | parallel_ping_delay | |
f1bf3249 | 303 | ) |
c1fff16a | 304 | ); |
f2c0a5db GMF |
305 | scheduler_list->push_back( scheduler ); |
306 | } | |
a85f210b CH |
307 | |
308 | return true; | |
f2c0a5db | 309 | } |
c1fff16a | 310 | |
f2c0a5db GMF |
311 | void start_pingers( |
312 | const PingSchedulerList &scheduler_list | |
313 | ) | |
314 | { | |
88714861 | 315 | // start each ping scheduler |
e01cc130 | 316 | BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list ) |
365036be | 317 | scheduler->start_pinging(); |
88714861 GMF |
318 | } |
319 | ||
320 | void stop_pingers( | |
321 | const PingSchedulerList &scheduler_list | |
322 | ) | |
323 | { | |
1d1ae364 TJ |
324 | // Stop each ping scheduler |
325 | GlobalLogger.info() << "Telling all pingers to stop"; | |
e01cc130 | 326 | BOOST_FOREACH( const PingSchedulerItem &scheduler, scheduler_list ) |
88714861 | 327 | { |
365036be | 328 | scheduler->stop_pinging(); |
88714861 | 329 | } |
0470811e | 330 | |
1ece191b | 331 | IcmpPacketDistributor::clean_up_all(); |
88714861 GMF |
332 | } |
333 | ||
35e8afe0 | 334 | |
365036be CH |
335 | // the one instance of signal_data_struct |
336 | signal_data_struct signal_data; | |
337 | ||
0fd358ca | 338 | |
666388ba CH |
339 | /// registered as signal handler; just sets signal_data.signaled_flag |
340 | void signal_handler_int(int param) | |
365036be | 341 | { |
963e98a2 | 342 | signal_data.signaled_flag_int = 1; |
666388ba CH |
343 | } |
344 | void signal_handler_term(int param) | |
345 | { | |
963e98a2 | 346 | signal_data.signaled_flag_term = 1; |
666388ba CH |
347 | } |
348 | void signal_handler_usr1(int param) | |
349 | { | |
963e98a2 | 350 | signal_data.signaled_flag_usr1 = 1; |
666388ba CH |
351 | } |
352 | void signal_handler_usr2(int param) | |
353 | { | |
963e98a2 | 354 | signal_data.signaled_flag_usr2 = 1; |
35e8afe0 TJ |
355 | } |
356 | ||
0fd358ca CH |
357 | |
358 | /// called regularly from io_service; checks signal_data.signal_flag | |
365036be | 359 | void signal_checker( const boost::system::error_code &error ) |
35e8afe0 | 360 | { |
365036be | 361 | bool want_stop = false; |
35e8afe0 | 362 | |
365036be CH |
363 | if ( error ) |
364 | { // there was an error in the timer | |
365 | if ( error == boost::asio::error::operation_aborted ) | |
35e8afe0 | 366 | { |
365036be CH |
367 | GlobalLogger.error() << "Signal check timer was cancelled! Stopping io_service" << endl; |
368 | want_stop = true; | |
0b920e26 GMF |
369 | } |
370 | else | |
371 | { | |
0fd358ca CH |
372 | GlobalLogger.error() << "Signal check timer handler received error code " << error |
373 | << "! Stopping io_service" << endl; | |
365036be | 374 | want_stop = true; |
0b920e26 | 375 | } |
35e8afe0 | 376 | } |
716deecb CH |
377 | else { |
378 | if ( signal_data.signaled_flag_int ) | |
379 | { | |
963e98a2 | 380 | signal_data.signaled_flag_int = 0; |
716deecb CH |
381 | GlobalLogger.notice() << "Received signal SIGINT --> will stop" << endl; |
382 | want_stop = true; | |
383 | } | |
384 | else if ( signal_data.signaled_flag_term ) | |
385 | { | |
963e98a2 | 386 | signal_data.signaled_flag_term = 0; |
716deecb CH |
387 | GlobalLogger.notice() << "Received signal SIGTERM --> will stop" << endl; |
388 | want_stop = true; | |
389 | } | |
390 | else if ( signal_data.signaled_flag_usr1 ) | |
365036be | 391 | { |
963e98a2 | 392 | signal_data.signaled_flag_usr1 = 0; |
365036be CH |
393 | int new_log_level = I2n::Logger::get_log_level()+1; |
394 | I2n::Logger::set_log_level( new_log_level ); | |
666388ba | 395 | GlobalLogger.info() << "Received SIGUSR1 -- increased log level to " |
365036be CH |
396 | << I2n::Logger::get_log_level_string(); |
397 | } | |
716deecb | 398 | else if ( signal_data.signaled_flag_usr2 ) |
365036be | 399 | { |
963e98a2 | 400 | signal_data.signaled_flag_usr2 = 0; |
365036be | 401 | I2n::Logger::set_log_level( signal_data.config_log_level ); |
666388ba | 402 | GlobalLogger.info() << "Received SIGUSR2 -- reset log level to normal (" |
365036be CH |
403 | << I2n::Logger::get_log_level_string() << ")"; |
404 | } | |
365036be | 405 | } |
fc7ae593 | 406 | |
365036be CH |
407 | if ( want_stop ) |
408 | { // interrupt infinite loop in main and asio event loop | |
409 | signal_data.stopped = true; | |
410 | signal_data.io_service->stop(); | |
fc7ae593 CH |
411 | } |
412 | else | |
365036be | 413 | { // re-schedule timer |
365036be CH |
414 | signal_data.check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL ); |
415 | signal_data.check_timer->async_wait( signal_checker ); | |
fc7ae593 CH |
416 | } |
417 | } | |
418 | ||
365036be | 419 | /// register own signal handlers; see reset_signal_handlers for undo |
666388ba | 420 | void install_signal_handlers( const IoServiceItem io_service, const int config_log_level ) |
fc7ae593 | 421 | { |
963e98a2 CH |
422 | signal_data.signaled_flag_int = 0; |
423 | signal_data.signaled_flag_term = 0; | |
424 | signal_data.signaled_flag_usr1 = 0; | |
425 | signal_data.signaled_flag_usr2 = 0; | |
365036be | 426 | signal_data.config_log_level = config_log_level; |
fc7ae593 CH |
427 | |
428 | // install own signal handlers | |
666388ba CH |
429 | signal_data.old_handler_int = signal(SIGINT, signal_handler_int); |
430 | signal_data.old_handler_term = signal(SIGTERM, signal_handler_term); | |
431 | signal_data.old_handler_usr1 = signal(SIGUSR1, signal_handler_usr1); | |
432 | signal_data.old_handler_usr2 = signal(SIGUSR2, signal_handler_usr2); | |
fc7ae593 CH |
433 | if ( signal_data.old_handler_int == SIG_ERR || |
434 | signal_data.old_handler_term == SIG_ERR || | |
435 | signal_data.old_handler_usr1 == SIG_ERR || | |
436 | signal_data.old_handler_usr2 == SIG_ERR ) | |
365036be CH |
437 | throw runtime_error( string("Failed to install signal handler: ") + string(strerror(errno)) ); |
438 | ||
439 | // create a timer and a shared pointer to it, so it does not get out of scope | |
440 | TimerItem check_timer( new boost::asio::deadline_timer( *io_service ) ); | |
fc7ae593 | 441 | |
365036be | 442 | // remember the io_service and the timer |
fc7ae593 | 443 | signal_data.io_service = io_service; |
365036be | 444 | signal_data.check_timer = check_timer; |
fc7ae593 | 445 | |
365036be CH |
446 | // set the timer |
447 | check_timer->expires_from_now( SIGNAL_CHECK_INTERVAL ); | |
448 | check_timer->async_wait( signal_checker ); | |
449 | GlobalLogger.debug() << "signal timer set" << endl; | |
fc7ae593 CH |
450 | } |
451 | ||
666388ba | 452 | /// reset handlers to the ones saved in install_signal_handlers |
365036be | 453 | void reset_signal_handlers() |
f2c0a5db | 454 | { |
425d0f07 CH |
455 | void (*old_handler_int)(int) = 0; |
456 | void (*old_handler_term)(int) = 0; | |
457 | void (*old_handler_usr1)(int) = 0; | |
458 | void (*old_handler_usr2)(int) = 0; | |
459 | if (signal_data.old_handler_int != 0 ) | |
460 | old_handler_int = signal(SIGINT , signal_data.old_handler_int); | |
461 | if (signal_data.old_handler_term != 0 ) | |
462 | old_handler_term = signal(SIGTERM, signal_data.old_handler_term); | |
463 | if (signal_data.old_handler_usr1 != 0 ) | |
464 | old_handler_usr1 = signal(SIGUSR1, signal_data.old_handler_usr1); | |
465 | if (signal_data.old_handler_usr2 != 0 ) | |
466 | old_handler_usr2 = signal(SIGUSR2, signal_data.old_handler_usr2); | |
365036be CH |
467 | |
468 | if ( old_handler_int == SIG_ERR || | |
469 | old_handler_term == SIG_ERR || | |
470 | old_handler_usr1 == SIG_ERR || | |
471 | old_handler_usr2 == SIG_ERR ) | |
472 | throw runtime_error( string("Failed to reset signal handler: ") + string(strerror(errno)) ); | |
473 | } | |
474 | ||
35e8afe0 | 475 | |
365036be CH |
476 | int main( int argc, const char *argv[] ) |
477 | { | |
88714861 | 478 | init_logger(); |
99ee8244 | 479 | GlobalLogger.debug() << "logger initiated with default config"; |
f2c0a5db | 480 | |
6e8c880d | 481 | PingSchedulerList scheduler_list; |
365036be | 482 | IoServiceItem io_service; |
6e8c880d | 483 | int ret_code = 0; |
ad83004d | 484 | |
6e8c880d | 485 | try |
f2c0a5db | 486 | { |
b588279a CH |
487 | GetConfigReturnType success_and_config = get_configuration( argc, argv ); |
488 | ConfigurationItem configuration = success_and_config.second; | |
489 | ||
490 | if ( configuration->get_print_version() ) // do this even if parsing of config failed | |
491 | { | |
a85f210b CH |
492 | GlobalLogger.debug() << "Printing version info (" |
493 | << VERSION_STRING << "." << VERSION_REVISION_STRING | |
494 | << " build " << __DATE__ | |
495 | << ") and exit" << endl; | |
496 | cout << PROJECT_NAME << " version " | |
497 | << VERSION_STRING << "." << VERSION_REVISION_STRING | |
498 | << " build " << __DATE__ | |
499 | << endl; | |
b588279a CH |
500 | return 0; |
501 | } | |
502 | ||
503 | if ( ! success_and_config.first ) | |
6e8c880d | 504 | { |
b588279a CH |
505 | GlobalLogger.error() << "Could not read/parse configuration!"; |
506 | GlobalLogger.debug() << "Return 1 immediately" << endl; | |
fc7ae593 CH |
507 | return 1; |
508 | } | |
b588279a | 509 | GlobalLogger.debug() << "Start setup" << endl; |
1d1ae364 | 510 | |
fc7ae593 | 511 | int log_level = configuration->get_log_level(); |
365036be | 512 | I2n::Logger::set_log_level( log_level ); |
fc7ae593 | 513 | GlobalLogger.info() << "Set LogLevel to " << I2n::Logger::get_log_level_string() << endl; |
5ba17410 | 514 | |
fc7ae593 | 515 | set_log_output( configuration ); |
a85f210b CH |
516 | GlobalLogger.notice() << "started pingcheck version " |
517 | << VERSION_STRING << "." << VERSION_REVISION_STRING | |
518 | << " build " << __DATE__ | |
519 | << endl; | |
f2c0a5db | 520 | |
fc7ae593 CH |
521 | bool daemon_mode = configuration->get_daemon(); |
522 | if ( daemon_mode ) | |
523 | { | |
524 | I2n::Daemon::daemonize(); | |
525 | } | |
f2c0a5db | 526 | |
fc7ae593 | 527 | LinkStatusItem status_notifier = get_status_notifier( configuration ); |
f2c0a5db | 528 | |
365036be CH |
529 | IoServiceItem io_service_temp( new boost::asio::io_service() ); |
530 | io_service_temp.swap( io_service ); | |
531 | io_service_temp.reset(); | |
fc7ae593 | 532 | |
9490a7bd CH |
533 | // create Dns master |
534 | boost::asio::ip::address name_server_ip = | |
535 | boost::asio::ip::address::from_string( | |
536 | configuration->get_nameserver() ); | |
a85f210b | 537 | int max_recursion_count = 10; // could make a config var some time |
9490a7bd CH |
538 | DnsMaster::create_master( |
539 | io_service, | |
540 | name_server_ip, | |
541 | configuration->get_resolved_ip_ttl_threshold(), | |
f833126b | 542 | configuration->get_min_time_between_resolves(), |
9490a7bd | 543 | configuration->get_max_address_resolution_attempts(), |
cd71d095 | 544 | max_recursion_count, |
9490a7bd CH |
545 | configuration->get_dns_cache_file() ); |
546 | ||
a85f210b CH |
547 | if ( !init_pingers(io_service, configuration, status_notifier, |
548 | &scheduler_list) ) | |
549 | { | |
550 | GlobalLogger.error() << "Could not initialize pingers or no hosts " | |
551 | << "given to ping --> exit"; | |
552 | return 2; | |
553 | } | |
fc7ae593 | 554 | |
666388ba | 555 | install_signal_handlers( io_service, log_level ); |
88714861 | 556 | |
365036be | 557 | start_pingers( scheduler_list ); |
6e8c880d | 558 | } |
aaff53da | 559 | catch ( const std::exception &ex ) |
6e8c880d | 560 | { |
fc7ae593 | 561 | GlobalLogger.error() << "Uncaught exception. " << ex.what() << endl; |
a85f210b | 562 | ret_code = 3; |
6e8c880d CH |
563 | } |
564 | catch (...) { | |
fc7ae593 | 565 | GlobalLogger.error() << "Caught unknown exception!" << endl; |
a85f210b | 566 | ret_code = 4; |
6e8c880d | 567 | } |
35e8afe0 | 568 | |
365036be | 569 | if ( ret_code == 0 ) |
fc7ae593 | 570 | { |
747c13ca | 571 | GlobalLogger.info() << "starting io_service main loop" << endl; |
ad83004d | 572 | |
365036be | 573 | // call boost::asio main event loop, catching exceptions |
7840efba CH |
574 | try |
575 | { | |
576 | io_service->run(); | |
577 | } | |
578 | catch ( const std::exception &ex ) | |
fc7ae593 | 579 | { |
7840efba CH |
580 | GlobalLogger.error() << "Caught exception, will continue. " << ex.what() << endl; |
581 | } | |
582 | catch (...) { | |
583 | GlobalLogger.error() << "Caught unknown exception, will continue!" << endl; | |
fc7ae593 CH |
584 | } |
585 | } | |
586 | ||
6e8c880d CH |
587 | // clean up |
588 | try | |
589 | { | |
590 | GlobalLogger.info() << "Cleaning up" << endl; | |
1d1ae364 | 591 | stop_pingers( scheduler_list ); |
365036be | 592 | reset_signal_handlers(); |
ced28dc7 | 593 | } |
aaff53da | 594 | catch ( const std::exception &ex ) |
6e8c880d | 595 | { |
fc7ae593 | 596 | GlobalLogger.error() << "Uncaught exception while cleaning up: " << ex.what() << endl; |
a85f210b | 597 | ret_code += 16; |
6e8c880d CH |
598 | } |
599 | catch (...) { | |
fc7ae593 | 600 | GlobalLogger.error() << "Caught unknown exception while cleaning up!" << endl; |
a85f210b | 601 | ret_code += 32; |
6e8c880d | 602 | } |
4ea9706c | 603 | |
365036be | 604 | GlobalLogger.notice() << "Pingcheck done " << endl; |
6e8c880d | 605 | return ret_code; |
4ea9706c | 606 | } |