b5d5bdbaa85470ca2a8af01bd55a11ab457453c8
[pingcheck] / src / host / hoststatus.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 "host/hoststatus.h"
21
22 #include <iostream>
23 #include <logfunc.hpp>
24
25 #include "boost_assert_handler.h"
26
27 using namespace std;
28 using I2n::Logger::GlobalLogger;
29
30 //-----------------------------------------------------------------------------
31 // HostStatus
32 //-----------------------------------------------------------------------------
33
34 /**
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
37  * fail.
38  * @param link_analyzer The object used to notify the status of the host.
39  */
40 HostStatus::HostStatus(
41         const string &host_address,
42         const int ping_fail_limit_percentage,
43         const LinkStatusItem link_analyzer
44 ) :
45     HostAddress( host_address ),
46     LinkAnalyzer( link_analyzer ),
47     PingFailLimitPercentage( ping_fail_limit_percentage ),
48     ResolvedIpCount( 0 ),
49     PingsPerformedCount( 0 ),
50     PingsFailedCount( 0 ),
51     ExceededPingFailedLimit( false )
52 {
53     BOOST_ASSERT( !HostAddress.empty() );
54     BOOST_ASSERT( ( 0 <= PingFailLimitPercentage ) && ( PingFailLimitPercentage <= 100 ) );
55 }
56
57 HostStatus::~HostStatus()
58 {
59 }
60
61 /**
62  * @param resolved_ip_count The number of IPs resolved for the host.
63  */
64 void HostStatus::set_resolved_ip_count( const int resolved_ip_count )
65 {
66     BOOST_ASSERT( 0 <= resolved_ip_count );
67
68     if (resolved_ip_count != ResolvedIpCount)
69     {   // assume that the target has changed --> reset counters
70         reset_ping_counters();
71     }
72     ResolvedIpCount = resolved_ip_count;
73
74     GlobalLogger.debug() << "Stat(" << HostAddress << "): "
75         << PingsFailedCount << " fail/" << PingsPerformedCount << " pings/"
76         << ResolvedIpCount << " IPs: #IPs set";
77 }
78
79 /**
80  * @return true if the amount of failed pings given to the host exceeded the
81  * limit.
82  */
83 bool HostStatus::exceeded_ping_failed_limit() const
84 {
85     return ExceededPingFailedLimit;
86 }
87
88 /**
89  * Tells the status analyzer how the last ping went
90  *
91  * @param result: status of ping specifying success/failure and reason of fail
92  * @param ping_duration_us duration of ping in micro seconds
93  */
94 void HostStatus::update_ping_statistics( const PingStatus &result,
95                                          const long ping_duration_us )
96 {
97     float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.;
98
99     GlobalLogger.debug() << "Stat(" << HostAddress << "): "
100         << PingsFailedCount << " fail/" << PingsPerformedCount << " pings/"
101         << ResolvedIpCount << " IPs: add ping with result "
102         << to_string(result) << " which took " << ping_duration_ms << " ms";
103
104     BOOST_ASSERT( 1 <= ResolvedIpCount );
105     BOOST_ASSERT( 0 <= PingsPerformedCount );
106     BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
107
108     increase_ping_performed_count();
109
110     if ( result != PingStatus_SuccessReply )
111     {
112         increase_ping_failed_count();
113     }
114
115     analyze_ping_failed_count();
116
117     // after we tried all IPs resolved for this host, we can analyze how many
118     // failed
119     if ( tried_all_resolved_ip() )
120     {
121         analyze_ping_statistics();
122
123         reset_ping_counters();
124     }
125
126     BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
127 }
128
129
130 bool HostStatus::tried_all_resolved_ip() const
131 {
132     BOOST_ASSERT( ( 0 < PingsPerformedCount ) && ( PingsPerformedCount <= ResolvedIpCount ) );
133
134     return ( PingsPerformedCount == ResolvedIpCount );
135 }
136
137 void HostStatus::analyze_ping_statistics()
138 {
139     BOOST_ASSERT( !HostAddress.empty() );
140     BOOST_ASSERT( PingsPerformedCount == ResolvedIpCount );
141
142     // notify if the amount of pings that failed exceed the limit
143     if ( exceeded_ping_failed_limit() )
144     {
145         GlobalLogger.debug() << "Stat(" << HostAddress << "): "
146             << PingsFailedCount << " fail/" << PingsPerformedCount << " pings/"
147             << ResolvedIpCount << " IPs: notify down";
148         LinkAnalyzer->notify_host_down( HostAddress );
149     }
150     else
151     {
152         GlobalLogger.debug() << "Stat(" << HostAddress << "): "
153             << PingsFailedCount << " fail/" << PingsPerformedCount << " pings/"
154             << ResolvedIpCount << " IPs: notify up";
155         LinkAnalyzer->notify_host_up( HostAddress );
156     }
157 } //lint !e1762
158
159 void HostStatus::reset_ping_counters()
160 {
161     PingsPerformedCount = 0;
162     PingsFailedCount = 0;
163 }
164
165 void HostStatus::increase_ping_performed_count()
166 {
167     ++PingsPerformedCount;
168
169     BOOST_ASSERT( ( 0 < PingsPerformedCount ) && ( PingsPerformedCount <= ResolvedIpCount ) );
170 }
171
172 void HostStatus::increase_ping_failed_count()
173 {
174     ++PingsFailedCount;
175
176     BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
177 }
178
179 void HostStatus::analyze_ping_failed_count()
180 {
181     BOOST_ASSERT( ( 0 <= PingFailLimitPercentage ) && ( PingFailLimitPercentage <= 100 ) );
182     BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
183
184     int ping_fail_limit_count = ( ResolvedIpCount * PingFailLimitPercentage ) / 100;
185
186     // keep a boolean variable because the PingsFailedCount can be reseted
187     if ( PingsFailedCount > ping_fail_limit_count )
188     {
189         ExceededPingFailedLimit = true;
190
191         GlobalLogger.debug() << "Stat(" << HostAddress << "): "
192             << PingsFailedCount << " fail/" << PingsPerformedCount << " pings/"
193             << ResolvedIpCount << " IPs: exceed limit=" << ping_fail_limit_count;
194     }
195     else
196     {
197         ExceededPingFailedLimit = false;
198
199         GlobalLogger.debug() << "Stat(" << HostAddress << "): "
200             << PingsFailedCount << " fail/" << PingsPerformedCount << " pings/"
201             << ResolvedIpCount << " IPs: below limit=" << ping_fail_limit_count;
202     }
203 }