use line digestion recognition in PingScheduler;
[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
ddf41c89
GMF
147 BOOST_ASSERT( 1 <= ResolvedIpCount );
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{
91aa83f9
CH
199 BOOST_ASSERT( ( 0 < PingsPerformedCount ) &&
200 ( PingsPerformedCount <= ResolvedIpCount*NParallelPingers ) );
d4793cc9 201
91aa83f9 202 return ( PingsPerformedCount == ResolvedIpCount*NParallelPingers );
d8a91bd6
GMF
203}
204
6c14bbee 205void HostStatus::analyze_ping_statistics()
ddf41c89 206{
c1fff16a 207 BOOST_ASSERT( !HostAddress.empty() );
91aa83f9 208 BOOST_ASSERT( PingsPerformedCount == ResolvedIpCount*NParallelPingers );
ddf41c89 209
c1fff16a 210 // notify if the amount of pings that failed exceed the limit
a341119a 211 if ( exceeded_ping_failed_limit() )
ddf41c89 212 {
a7b15639 213 GlobalLogger.debug() << log_prefix() << "notify down";
fb469ffa 214 LinkAnalyzer->notify_host_down( HostAddress );
ddf41c89
GMF
215 }
216 else
217 {
a7b15639 218 GlobalLogger.debug() << log_prefix() << "notify up";
fb469ffa 219 LinkAnalyzer->notify_host_up( HostAddress );
ddf41c89 220 }
a7b15639
CH
221
222 // nothing to do about congestion here, congestion is not forwarded to
223 // central LinkAnalyzer
6fd0993e 224} //lint !e1762
ddf41c89 225
6c14bbee 226void HostStatus::reset_ping_counters()
c1fff16a
GMF
227{
228 PingsPerformedCount = 0;
229 PingsFailedCount = 0;
a7b15639 230 PingCongestionCount = 0;
c1fff16a
GMF
231}
232
6c14bbee 233void HostStatus::increase_ping_performed_count()
c5e4bfa1
GMF
234{
235 ++PingsPerformedCount;
c1fff16a 236
91aa83f9
CH
237 BOOST_ASSERT( ( 0 < PingsPerformedCount ) &&
238 ( PingsPerformedCount <= ResolvedIpCount*NParallelPingers ) );
c5e4bfa1
GMF
239}
240
6c14bbee 241void HostStatus::increase_ping_failed_count()
c5e4bfa1
GMF
242{
243 ++PingsFailedCount;
c1fff16a
GMF
244
245 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
c5e4bfa1
GMF
246}
247
a7b15639
CH
248void HostStatus::increase_ping_congestion_count()
249{
250 ++PingCongestionCount;
251
252 BOOST_ASSERT( ( 0 <= PingCongestionCount )
253 && ( PingCongestionCount <= PingsPerformedCount ) );
254}
255
6c14bbee 256void HostStatus::analyze_ping_failed_count()
ddf41c89 257{
cd4048df 258 BOOST_ASSERT( ( 0 <= PingFailLimitPercentage ) && ( PingFailLimitPercentage <= 100 ) );
c1fff16a
GMF
259 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
260
91aa83f9
CH
261 int ping_fail_limit_count = ( ResolvedIpCount * PingFailLimitPercentage
262 * NParallelPingers) / 100;
c1fff16a 263
6827496c 264 // keep a boolean variable because the PingsFailedCount can be reseted
cd4048df 265 if ( PingsFailedCount > ping_fail_limit_count )
1d7d7cb2
GMF
266 {
267 ExceededPingFailedLimit = true;
3f7c921f 268
a7b15639
CH
269 GlobalLogger.debug() << log_prefix() << "exceed fail limit="
270 << ping_fail_limit_count;
1d7d7cb2
GMF
271 }
272 else
273 {
274 ExceededPingFailedLimit = false;
3f7c921f 275
a7b15639
CH
276 GlobalLogger.debug() << log_prefix() << "below fail limit="
277 << ping_fail_limit_count;
278 }
279}
280
281void HostStatus::analyze_ping_congestion_count()
282{
283 BOOST_ASSERT( ( 0 <= PingCongestionLimitPercentage )
284 && ( PingCongestionLimitPercentage <= 100 ) );
285 BOOST_ASSERT( ( 0 <= PingCongestionCount )
286 && ( PingCongestionCount <= PingsPerformedCount ) );
287
288 int ping_congestion_limit_count = ( ResolvedIpCount * NParallelPingers
289 * PingCongestionLimitPercentage ) / 100;
290
291 // keep a boolean variable because the PingCongestionCount can be reseted
292 if ( PingCongestionCount > ping_congestion_limit_count )
293 {
294 ExceededPingCongestionLimit = true;
295
296 GlobalLogger.debug() << log_prefix() << "exceed congestion limit="
297 << ping_congestion_limit_count;
298 }
299 else
300 {
301 ExceededPingCongestionLimit = false;
302
303 GlobalLogger.debug() << log_prefix() << "below congestion limit="
304 << ping_congestion_limit_count;
1d7d7cb2 305 }
c5e4bfa1 306}