removed assertion in HostStatus that PingsPerformedCount <= ResolvedIpCount*NParallel...
[pingcheck] / src / host / hoststatus.cpp
CommitLineData
91fcc471
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
6c14bbee 20#include "host/hoststatus.h"
ddf41c89
GMF
21
22#include <iostream>
3f7c921f 23#include <logfunc.hpp>
ddf41c89 24
780b0bca 25#include "boost_assert_handler.h"
ddf41c89
GMF
26
27using namespace std;
3f7c921f 28using I2n::Logger::GlobalLogger;
ddf41c89
GMF
29
30//-----------------------------------------------------------------------------
6c14bbee 31// HostStatus
ddf41c89
GMF
32//-----------------------------------------------------------------------------
33
c01a6023 34/**
6c14bbee
GMF
35 * @param host_address The address of the host it has to analyze.
36 * @param ping_fail_percentage_limit The percentage threshold of pings that can
c01a6023 37 * fail.
a7b15639
CH
38 * @param ping_congestion_limit_percentage The percentage threshold of pings
39 * that can fail due to line congestion
40 * @param ping_duration_congestion_thresh Threshold in micro seconds that marks
41 * the difference between a "normal" and a congested line
42 * @param n_parallel_pings Number of pings that is sent for each IP
6c14bbee 43 * @param link_analyzer The object used to notify the status of the host.
c01a6023 44 */
6c14bbee 45HostStatus::HostStatus(
ddf41c89 46 const string &host_address,
cd4048df 47 const int ping_fail_limit_percentage,
a7b15639
CH
48 const int ping_congestion_limit_percentage,
49 const int ping_duration_congestion_thresh,
91aa83f9 50 const int n_parallel_pings,
c6c54dfb 51 const LinkStatusItem link_analyzer
ddf41c89 52) :
c1fff16a 53 HostAddress( host_address ),
fb469ffa 54 LinkAnalyzer( link_analyzer ),
cd4048df 55 PingFailLimitPercentage( ping_fail_limit_percentage ),
a7b15639
CH
56 PingCongestionLimitPercentage( ping_congestion_limit_percentage ),
57 PingDurationCongestionsThresh( ping_duration_congestion_thresh*1000000 ),
ddf41c89
GMF
58 ResolvedIpCount( 0 ),
59 PingsPerformedCount( 0 ),
d8a91bd6 60 PingsFailedCount( 0 ),
a7b15639 61 PingCongestionCount( 0 ),
91aa83f9 62 ExceededPingFailedLimit( false ),
a7b15639 63 ExceededPingCongestionLimit( false ),
91aa83f9 64 NParallelPingers( n_parallel_pings)
ddf41c89 65{
d4793cc9 66 BOOST_ASSERT( !HostAddress.empty() );
a7b15639
CH
67 BOOST_ASSERT( ( 0 <= PingFailLimitPercentage )
68 && ( PingFailLimitPercentage <= 100 ) );
69 BOOST_ASSERT( ( 0 <= PingCongestionLimitPercentage )
70 && ( PingCongestionLimitPercentage <= 100 ) );
ddf41c89
GMF
71}
72
6c14bbee 73HostStatus::~HostStatus()
ddf41c89
GMF
74{
75}
76
a7b15639 77
242e5fb3
CH
78void HostStatus::set_n_parallel_pings(const int n_parallel_pings)
79{
80 if (NParallelPingers != n_parallel_pings)
81 {
82 NParallelPingers = n_parallel_pings;
83 reset_ping_counters();
84 }
85 GlobalLogger.debug() << log_prefix() << "#pingers set";
86}
87
88
a7b15639
CH
89std::string HostStatus::log_prefix()
90{
91 std::stringstream temp;
92 temp << "Stat(" << HostAddress << "): "
93 << PingsFailedCount << " fail," << PingCongestionCount << " cong/"
94 << PingsPerformedCount << " pings/" << ResolvedIpCount << "*"
95 << NParallelPingers << " IPs: ";
242e5fb3 96 return temp.str();
a7b15639
CH
97}
98
c01a6023 99/**
6c14bbee 100 * @param resolved_ip_count The number of IPs resolved for the host.
c01a6023 101 */
6c14bbee 102void HostStatus::set_resolved_ip_count( const int resolved_ip_count )
ddf41c89 103{
838e0acf 104 BOOST_ASSERT( 0 <= resolved_ip_count );
ddf41c89 105
db625177
CH
106 if (resolved_ip_count != ResolvedIpCount)
107 { // assume that the target has changed --> reset counters
108 reset_ping_counters();
109 }
ddf41c89 110 ResolvedIpCount = resolved_ip_count;
3f7c921f 111
a7b15639 112 GlobalLogger.debug() << log_prefix() << "#IPs set";
ddf41c89
GMF
113}
114
c01a6023
GMF
115/**
116 * @return true if the amount of failed pings given to the host exceeded the
117 * limit.
118 */
6c14bbee 119bool HostStatus::exceeded_ping_failed_limit() const
d8a91bd6 120{
a341119a 121 return ExceededPingFailedLimit;
d8a91bd6
GMF
122}
123
c01a6023 124/**
a7b15639
CH
125 * @return true if the amount of congested pings given to the host exceeded the
126 * limit.
127 */
128bool HostStatus::exceeded_ping_congestion_limit() const
129{
130 return ExceededPingCongestionLimit;
131}
132
133/**
96c4e7a4
CH
134 * Tells the status analyzer how the last ping went
135 *
136 * @param result: status of ping specifying success/failure and reason of fail
137 * @param ping_duration_us duration of ping in micro seconds
c01a6023 138 */
96c4e7a4
CH
139void HostStatus::update_ping_statistics( const PingStatus &result,
140 const long ping_duration_us )
ddf41c89 141{
242e5fb3 142 float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.0f;
96c4e7a4 143
a7b15639
CH
144 GlobalLogger.debug() << log_prefix() << "add ping with result "
145 << to_string(result) << " which took " << ping_duration_ms << " ms";
3f7c921f 146
ffa5cfe2 147 BOOST_ASSERT( 0 <= ResolvedIpCount );
ddf41c89
GMF
148 BOOST_ASSERT( 0 <= PingsPerformedCount );
149 BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
a7b15639 150 BOOST_ASSERT( PingCongestionCount <= PingsPerformedCount );
ddf41c89 151
a7b15639
CH
152 update_fail_stats( result );
153 update_congestion_stats( result, ping_duration_us );
2c10f87b 154
c5e4bfa1
GMF
155 // after we tried all IPs resolved for this host, we can analyze how many
156 // failed
157 if ( tried_all_resolved_ip() )
ddf41c89 158 {
d8a91bd6 159 analyze_ping_statistics();
ddf41c89 160
c5e4bfa1 161 reset_ping_counters();
ddf41c89
GMF
162 }
163
164 BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
a7b15639
CH
165 BOOST_ASSERT( PingCongestionCount <= PingsPerformedCount );
166}
167
168
169void HostStatus::update_fail_stats( const PingStatus &result)
170{
171 increase_ping_performed_count();
172
173 if ( result != PingStatus_SuccessReply
174 && result != PingStatus_SuccessOutdatedIP)
175 {
176 increase_ping_failed_count();
177 }
178
179 analyze_ping_failed_count();
180}
181
182
183void HostStatus::update_congestion_stats( const PingStatus &result,
184 const long ping_duration_us )
185{
186 if (ping_duration_us > PingDurationCongestionsThresh)
187 increase_ping_congestion_count();
188 else if ( result == PingStatus_FailureTimeout )
189 increase_ping_congestion_count();
190 // PingStatus_FailureNoIP, PingStatus_SuccessOutdatedIP could also be caused
191 // by congestion, but also by other reasons (e.g. firewall blocking port 53)
192
193 analyze_ping_congestion_count();
ddf41c89
GMF
194}
195
c1d776ba 196
6c14bbee 197bool HostStatus::tried_all_resolved_ip() const
d8a91bd6 198{
ffa5cfe2 199 BOOST_ASSERT( 0 < PingsPerformedCount );
d4793cc9 200
ffa5cfe2 201 return ( PingsPerformedCount >= ResolvedIpCount*NParallelPingers );
d8a91bd6
GMF
202}
203
6c14bbee 204void HostStatus::analyze_ping_statistics()
ddf41c89 205{
c1fff16a 206 BOOST_ASSERT( !HostAddress.empty() );
ffa5cfe2 207 BOOST_ASSERT( PingsPerformedCount >= ResolvedIpCount*NParallelPingers );
ddf41c89 208
c1fff16a 209 // notify if the amount of pings that failed exceed the limit
a341119a 210 if ( exceeded_ping_failed_limit() )
ddf41c89 211 {
a7b15639 212 GlobalLogger.debug() << log_prefix() << "notify down";
fb469ffa 213 LinkAnalyzer->notify_host_down( HostAddress );
ddf41c89
GMF
214 }
215 else
216 {
a7b15639 217 GlobalLogger.debug() << log_prefix() << "notify up";
fb469ffa 218 LinkAnalyzer->notify_host_up( HostAddress );
ddf41c89 219 }
a7b15639
CH
220
221 // nothing to do about congestion here, congestion is not forwarded to
222 // central LinkAnalyzer
6fd0993e 223} //lint !e1762
ddf41c89 224
6c14bbee 225void HostStatus::reset_ping_counters()
c1fff16a
GMF
226{
227 PingsPerformedCount = 0;
228 PingsFailedCount = 0;
a7b15639 229 PingCongestionCount = 0;
c1fff16a
GMF
230}
231
6c14bbee 232void HostStatus::increase_ping_performed_count()
c5e4bfa1
GMF
233{
234 ++PingsPerformedCount;
c1fff16a 235
ffa5cfe2 236 BOOST_ASSERT( 0 < PingsPerformedCount );
c5e4bfa1
GMF
237}
238
6c14bbee 239void HostStatus::increase_ping_failed_count()
c5e4bfa1
GMF
240{
241 ++PingsFailedCount;
c1fff16a
GMF
242
243 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
c5e4bfa1
GMF
244}
245
a7b15639
CH
246void HostStatus::increase_ping_congestion_count()
247{
248 ++PingCongestionCount;
249
250 BOOST_ASSERT( ( 0 <= PingCongestionCount )
251 && ( PingCongestionCount <= PingsPerformedCount ) );
252}
253
6c14bbee 254void HostStatus::analyze_ping_failed_count()
ddf41c89 255{
cd4048df 256 BOOST_ASSERT( ( 0 <= PingFailLimitPercentage ) && ( PingFailLimitPercentage <= 100 ) );
c1fff16a
GMF
257 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
258
91aa83f9
CH
259 int ping_fail_limit_count = ( ResolvedIpCount * PingFailLimitPercentage
260 * NParallelPingers) / 100;
c1fff16a 261
6827496c 262 // keep a boolean variable because the PingsFailedCount can be reseted
cd4048df 263 if ( PingsFailedCount > ping_fail_limit_count )
1d7d7cb2
GMF
264 {
265 ExceededPingFailedLimit = true;
3f7c921f 266
a7b15639
CH
267 GlobalLogger.debug() << log_prefix() << "exceed fail limit="
268 << ping_fail_limit_count;
1d7d7cb2
GMF
269 }
270 else
271 {
272 ExceededPingFailedLimit = false;
3f7c921f 273
a7b15639
CH
274 GlobalLogger.debug() << log_prefix() << "below fail limit="
275 << ping_fail_limit_count;
276 }
277}
278
279void HostStatus::analyze_ping_congestion_count()
280{
281 BOOST_ASSERT( ( 0 <= PingCongestionLimitPercentage )
282 && ( PingCongestionLimitPercentage <= 100 ) );
283 BOOST_ASSERT( ( 0 <= PingCongestionCount )
284 && ( PingCongestionCount <= PingsPerformedCount ) );
285
286 int ping_congestion_limit_count = ( ResolvedIpCount * NParallelPingers
287 * PingCongestionLimitPercentage ) / 100;
288
289 // keep a boolean variable because the PingCongestionCount can be reseted
290 if ( PingCongestionCount > ping_congestion_limit_count )
291 {
292 ExceededPingCongestionLimit = true;
293
294 GlobalLogger.debug() << log_prefix() << "exceed congestion limit="
295 << ping_congestion_limit_count;
296 }
297 else
298 {
299 ExceededPingCongestionLimit = false;
300
301 GlobalLogger.debug() << log_prefix() << "below congestion limit="
302 << ping_congestion_limit_count;
1d7d7cb2 303 }
c5e4bfa1 304}