added option min-time-between-resolves-option and tests for it
[pingcheck] / src / config / configuration.cpp
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 */
20 #include "config/configuration.h"
21
22 #include <set>
23 #include <ctime>   // for seeding random number generator
24 #include <boost/math/special_functions/round.hpp>
25 #include <boost/numeric/conversion/cast.hpp>
26 #include <boost/foreach.hpp>
27 #include <boost/random/uniform_int.hpp>
28 #include <boost/random/variate_generator.hpp>
29
30 #include "boost_assert_handler.h"
31
32 using namespace std;
33 using I2n::Logger::LogLevel;
34 using I2n::Logger::GlobalLogger;
35
36 typedef boost::uniform_int<> rand_dist_type;
37 typedef boost::variate_generator<rand_gen_type&, rand_dist_type> rand_var_type;
38
39 //-----------------------------------------------------------------------------
40 // Configuration
41 //-----------------------------------------------------------------------------
42
43 Configuration::Configuration() :
44     Daemon( false ),
45     LoggingLevel( LogLevel::Error ),
46     LoggingOutput( LogOutput_SYSLOG ),
47     LogFileName( "" ),
48     ConfigFileName( "" ),
49     SourceNetworkInterface( "" ),
50     NameServer( "" ),
51     HostsDownLimit( 0 ),
52     MinHostsDownLimit( 0 ),
53     MaxHostsDownLimit( 50 ),
54     PingFailLimit( 0 ),
55     MinPingFailLimit( 0 ),
56     MaxPingFailLimit( 100 ),
57     StatusNotifierCmd( "" ),
58     LinkUpIntervalInMin( 0 ),
59     LinkDownIntervalInMin( 0 ),
60     MinStableLinkIntervalInMin( 0 ),
61     MaxStableLinkIntervalInMin( 60 ),
62     PingReplyTimeout( 30 ),
63     MaxAddressResolutionAttempts( 10 ),
64     ResolvedIpTtlThreshold( 10 ),
65     MinTimeBetweenResolves( 10 ),
66     DnsCacheFile(""),
67     Hosts(),
68     RatioRandomHosts( 1.0f ),
69     PrintVersion( false ),
70     RandomNumberGenerator( boost::numeric_cast<unsigned int>(time(0)) )
71 {
72 }
73
74 Configuration::~Configuration()
75 {
76 }
77
78 bool Configuration::get_daemon() const
79 {
80     return Daemon;
81 }
82
83 void Configuration::set_daemon( bool daemon )
84 { //lint !e578
85     Daemon = daemon;
86 }
87
88 LogLevel Configuration::get_log_level() const
89 {
90     return LoggingLevel;
91 }
92
93 void Configuration::set_log_level( const LogLevel &log_level )
94 {
95     BOOST_ASSERT( (LogLevel::Emergency <= log_level) && (log_level <= LogLevel::Debug) );
96
97     this->LoggingLevel = log_level;
98 }
99
100 LogOutput Configuration::get_log_output() const
101 {
102     return LoggingOutput;
103 }
104
105 void Configuration::set_log_output( const LogOutput &log_output )
106 {
107     BOOST_ASSERT( (LogOutput_First <= log_output) && (log_output <= LogOutput_Last) );
108
109     this->LoggingOutput = log_output;
110 }
111
112 string Configuration::get_log_file() const
113 {
114     return LogFileName;
115 }
116
117 void Configuration::set_log_file( const std::string &log_file )
118 {
119     BOOST_ASSERT( !log_file.empty() );
120
121     this->LogFileName = log_file;
122 }
123
124 string Configuration::get_config_file_name() const
125 {
126     return ConfigFileName;
127 }
128
129 void Configuration::set_config_file_name( const string &config_file_name )
130 {
131     BOOST_ASSERT( !config_file_name.empty() );
132
133     this->ConfigFileName = config_file_name;
134 }
135
136 string Configuration::get_nameserver() const
137 {
138     return NameServer;
139 }
140
141 void Configuration::set_nameserver( const string &nameserver )
142 {
143     NameServer = nameserver;
144 }
145
146 string Configuration::get_source_network_interface() const
147 {
148     return SourceNetworkInterface;
149 }
150
151 void Configuration::set_source_network_interface(
152         const string &source_network_interface
153 )
154 {
155     SourceNetworkInterface = source_network_interface;
156 }
157
158 int Configuration::get_hosts_down_limit() const
159 {
160     return HostsDownLimit;
161 }
162
163 void Configuration::set_hosts_down_limit( const int hosts_down_limit )
164 {
165     BOOST_ASSERT( ( MinHostsDownLimit <= hosts_down_limit ) && ( hosts_down_limit <= MaxHostsDownLimit ) );
166
167     this->HostsDownLimit = hosts_down_limit;
168 }
169
170 int Configuration::get_ping_fail_limit() const
171 {
172     return PingFailLimit;
173 }
174
175 void Configuration::set_ping_fail_limit( const int ping_fail_limit )
176 {
177     BOOST_ASSERT( ( MinPingFailLimit <= ping_fail_limit ) && ( ping_fail_limit <= MaxPingFailLimit ) );
178
179     PingFailLimit = ping_fail_limit;
180 }
181
182 string Configuration::get_status_notifier_cmd() const
183 {
184     return StatusNotifierCmd;
185 }
186
187 void Configuration::set_status_notifier_cmd( const string &status_notifier_cmd )
188 {
189     BOOST_ASSERT( !status_notifier_cmd.empty() );
190
191     StatusNotifierCmd = status_notifier_cmd;
192 }
193
194 int Configuration::get_link_up_interval_in_min() const
195 {
196     return LinkUpIntervalInMin;
197 }
198
199 void Configuration::set_link_up_interval_in_min(
200         const int link_up_interval_in_min
201 )
202 {
203     BOOST_ASSERT( ( MinStableLinkIntervalInMin <= link_up_interval_in_min ) && ( link_up_interval_in_min <= MaxStableLinkIntervalInMin ) );
204
205     LinkUpIntervalInMin = link_up_interval_in_min;
206 }
207
208 int Configuration::get_link_down_interval_in_min() const
209 {
210     return LinkDownIntervalInMin;
211 }
212
213 void Configuration::set_link_down_interval_in_min(
214         const int link_down_interval_in_min
215 )
216 {
217     BOOST_ASSERT( ( MinStableLinkIntervalInMin <= link_down_interval_in_min ) && ( link_down_interval_in_min <= MaxStableLinkIntervalInMin ) );
218
219     LinkDownIntervalInMin = link_down_interval_in_min;
220 }
221
222 int Configuration::get_ping_reply_timeout() const
223 {
224     return PingReplyTimeout;
225 }
226 void Configuration::set_ping_reply_timeout( const int ping_reply_timeout )
227 {
228     BOOST_ASSERT(ping_reply_timeout > 0 );
229     PingReplyTimeout = ping_reply_timeout;
230 }
231
232 int Configuration::get_max_address_resolution_attempts() const
233 {
234     return MaxAddressResolutionAttempts;
235 }
236 void Configuration::set_max_address_resolution_attempts( const int max_address_resolution_attempts )
237 {
238     BOOST_ASSERT(max_address_resolution_attempts > 0 );
239     MaxAddressResolutionAttempts = max_address_resolution_attempts;
240 }
241
242 int Configuration::get_resolved_ip_ttl_threshold() const
243 {
244     return ResolvedIpTtlThreshold;
245 }
246 void Configuration::set_resolved_ip_ttl_threshold( const int resolved_ip_ttl_threshold )
247 {
248     BOOST_ASSERT(resolved_ip_ttl_threshold >= 0 );
249     ResolvedIpTtlThreshold = resolved_ip_ttl_threshold;
250 }
251
252 int Configuration::get_min_time_between_resolves() const
253 {
254     return MinTimeBetweenResolves;
255 }
256 void Configuration::set_min_time_between_resolves( const int min_time_between_resolves )
257 {
258     BOOST_ASSERT(min_time_between_resolves >= 0 );
259     MinTimeBetweenResolves = min_time_between_resolves;
260 }
261
262 void Configuration::set_dns_cache_file( const std::string &dns_cache_file)
263 {
264     BOOST_ASSERT( !dns_cache_file.empty() );
265     DnsCacheFile = dns_cache_file;
266 }
267
268 std::string Configuration::get_dns_cache_file() const
269 {
270     return DnsCacheFile;
271 }
272
273 float Configuration::get_ratio_random_hosts() const
274 {
275     return RatioRandomHosts;
276 }
277
278 void Configuration::set_ratio_random_hosts( const float ratio )
279 {
280     BOOST_ASSERT( (ratio > 0.0f) && (ratio <= 1.0f) );
281     RatioRandomHosts = ratio;
282 }
283
284 HostList Configuration::get_hosts() const
285 {
286     return Hosts;
287 }
288
289 void Configuration::set_hosts( const HostList &hosts_list )
290 {
291     Hosts = hosts_list;
292 }
293
294 bool Configuration::get_print_version()
295 {
296     return PrintVersion;
297 }
298
299 void Configuration::set_print_version( const bool do_print )
300 {
301     PrintVersion = do_print;
302 }
303
304 int Configuration::get_random_number(const int lowest, const int highest)
305 {
306     rand_dist_type random_distribution(lowest, highest);
307     rand_var_type random_variate(RandomNumberGenerator, random_distribution);
308     return random_variate();
309 }
310
311 /**
312  * @brief select RatioRandomHosts of the hosts at random.
313  * changes internal list of hosts
314  * @returns false if could not randomize (e.g. only 1 host
315  *   available or ratio=1)
316  */
317 bool Configuration::randomize_hosts()
318 {
319     // need this a few times
320     unsigned int n_hosts = Hosts.size();
321     float n_hosts_float = boost::numeric_cast<float>(n_hosts);
322
323     // check if RatioRandomHosts == 1
324     if ((1. - RatioRandomHosts) < 0.5/n_hosts_float)
325         return false;
326
327     // determine number of hosts to keep
328     unsigned int n_wanted = boost::math::iround(n_hosts_float * RatioRandomHosts);
329     if (n_wanted == 0)
330         n_wanted = 1; // want at least 1 host
331     if (n_wanted == n_hosts)   // e.g. always the case if only 1 host given
332         return false;
333
334     GlobalLogger.info() << "randomizing hosts: keeping "
335                 << n_wanted << " from overall " << n_hosts;
336
337     BOOST_ASSERT(n_wanted <= n_hosts);   // just to be sure
338
339     // create new set of hosts (more efficient than removal from std::vector Hosts)
340     std::set<HostItem> new_hosts;
341     int take_idx;
342
343     // add hosts at random until size is good
344     rand_dist_type random_distribution(0, n_hosts-1);
345     rand_var_type random_variate(RandomNumberGenerator, random_distribution);
346     while (new_hosts.size() < n_wanted)
347     {
348         take_idx = random_variate();
349         new_hosts.insert( Hosts[take_idx] ); // does nothing if host is already in there
350     }
351
352     // convert from set to list
353     HostList new_list;
354     BOOST_FOREACH(HostItem host, new_hosts)
355         new_list.push_back(host);
356
357     this->Hosts = new_list;
358
359     return true;
360 }
361