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