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 | */ | |
72e54d1c | 20 | #include "link/linkstatus.h" |
ddf41c89 GMF |
21 | |
22 | #include <iostream> | |
23 | ||
301610ca GMF |
24 | #include <logfunc.hpp> |
25 | ||
e638894d CH |
26 | #include "dns/dnsmaster.h" |
27 | ||
780b0bca CH |
28 | #include "boost_assert_handler.h" |
29 | ||
ddf41c89 | 30 | using namespace std; |
2bf8720f GMF |
31 | using boost::posix_time::microsec_clock; |
32 | using boost::posix_time::ptime; | |
301610ca | 33 | using I2n::Logger::GlobalLogger; |
ddf41c89 GMF |
34 | |
35 | //----------------------------------------------------------------------------- | |
72e54d1c | 36 | // LinkStatus |
ddf41c89 GMF |
37 | //----------------------------------------------------------------------------- |
38 | ||
5a3f6189 GMF |
39 | /** |
40 | * @brief Creates a link status object. | |
41 | * | |
72e54d1c | 42 | * @param hosts_down_limit The maximum amount of different hosts that can be |
5a3f6189 | 43 | * down before the system take any action. |
72e54d1c | 44 | * @param link_up_interval_in_min The amount of time required to the link to |
5a3f6189 | 45 | * stay up before notify. |
72e54d1c | 46 | * @param link_down_interval_in_min The amount of time required to the link to |
5a3f6189 | 47 | * stay down before notify. |
72e54d1c | 48 | * @param status_notifier_cmd The command used to notify about link status |
5a3f6189 GMF |
49 | * changes. |
50 | */ | |
72e54d1c | 51 | LinkStatus::LinkStatus( |
a341119a | 52 | const int hosts_down_limit, |
f1bf3249 | 53 | const int link_up_interval_in_min, |
1634f2a1 | 54 | const int link_down_interval_in_min, |
b279ae09 | 55 | const string &status_notifier_cmd |
c1fff16a | 56 | ) : |
a341119a | 57 | HostsDownLimit( hosts_down_limit ), |
f1bf3249 GMF |
58 | HostsDownList(), |
59 | LinkUpIntervalInMin( link_up_interval_in_min ), | |
1634f2a1 | 60 | LinkDownIntervalInMin( link_down_interval_in_min ), |
72e54d1c | 61 | CurrentLinkStatus( Status_Down ), |
f1bf3249 GMF |
62 | CurrentNotificationStatus( NotificationStatus_NotReported ), |
63 | TimeLinkStatusChanged( microsec_clock::universal_time() ), | |
365036be | 64 | StatusNotifierCmd( new StatusNotifierCommand( status_notifier_cmd ) ) |
ddf41c89 | 65 | { |
a341119a | 66 | BOOST_ASSERT( 0 <= hosts_down_limit ); |
f1bf3249 | 67 | BOOST_ASSERT( 0 <= link_up_interval_in_min ); |
1634f2a1 | 68 | BOOST_ASSERT( 0 <= link_down_interval_in_min ); |
ddf41c89 GMF |
69 | } |
70 | ||
72e54d1c | 71 | LinkStatus::~LinkStatus() |
ddf41c89 GMF |
72 | { |
73 | } | |
74 | ||
5a3f6189 GMF |
75 | /** |
76 | * @brief Notify the system that a given host is up. The object takes an | |
77 | * appropriated action to deal with that. | |
78 | * Note: this object does not resolves IPs, thus you have to send the same host | |
79 | * address in order to the object to consider the same host. | |
80 | * | |
81 | * @param host_address the DNS/IP address of the host that is up. | |
82 | */ | |
72e54d1c | 83 | void LinkStatus::notify_host_up( const string &host_address ) |
ddf41c89 | 84 | { |
c1fff16a GMF |
85 | BOOST_ASSERT( !host_address.empty() ); |
86 | ||
f5ffc5df | 87 | bool has_changed = add_host_up( host_address ); |
c1fff16a | 88 | |
f5ffc5df CH |
89 | if (has_changed) |
90 | GlobalLogger.notice() << "Status (" << HostsDownList.size() | |
91 | << "/" << HostsDownLimit << " down): now up again is " | |
e638894d | 92 | << DnsMaster::get_cname_chain_str(host_address) << endl; |
f5ffc5df CH |
93 | else // less important so log only at info level |
94 | GlobalLogger.info() << "Status (" << HostsDownList.size() | |
95 | << "/" << HostsDownLimit << " down): still up is " | |
e638894d | 96 | << DnsMaster::get_cname_chain_str(host_address) << endl; |
1266407a | 97 | |
a341119a | 98 | if ( !exceeded_host_down_limit() ) |
1266407a | 99 | { |
fb469ffa | 100 | notify_link_up(); |
1266407a GMF |
101 | } |
102 | ||
b279ae09 | 103 | // removed from the list? |
1266407a | 104 | BOOST_ASSERT( HostsDownList.count( host_address ) == 0 ); |
529e5587 | 105 | } //lint !e1788 |
ddf41c89 | 106 | |
5a3f6189 GMF |
107 | /** |
108 | * @brief Notify the system that a given host is down. The object takes an | |
109 | * appropriated action to deal with that. | |
110 | * Note: this object does not resolves IPs, thus you have to send the same host | |
111 | * address in order to the object to consider the same host. | |
112 | * | |
72e54d1c | 113 | * @param host_address The DNS/IP address of the host that is down. |
5a3f6189 | 114 | */ |
72e54d1c | 115 | void LinkStatus::notify_host_down( const string &host_address ) |
ddf41c89 | 116 | { |
c1fff16a GMF |
117 | BOOST_ASSERT( !host_address.empty() ); |
118 | ||
1266407a | 119 | add_host_down( host_address ); |
c1fff16a | 120 | |
f5ffc5df CH |
121 | // report this always at notice level |
122 | GlobalLogger.notice() << "Status (" << HostsDownList.size() | |
123 | << "/" << HostsDownLimit << " down): down is " | |
e638894d | 124 | << DnsMaster::get_cname_chain_str(host_address) << endl; |
f5ffc5df | 125 | |
a341119a | 126 | if ( exceeded_host_down_limit() ) |
1266407a | 127 | { |
fb469ffa | 128 | notify_link_down(); |
1266407a | 129 | } |
c1fff16a | 130 | |
b279ae09 | 131 | // inserted in the list? |
1266407a | 132 | BOOST_ASSERT( HostsDownList.count( host_address ) == 1 ); |
529e5587 | 133 | } //lint !e1788 |
c1fff16a | 134 | |
f5ffc5df CH |
135 | // returns true if this did change something (i.e. host had been down) |
136 | bool LinkStatus::add_host_up( const string &host_address ) | |
1266407a GMF |
137 | { |
138 | if ( HostsDownList.count( host_address ) > 0 ) | |
139 | { | |
a4049623 GMF |
140 | size_t erased_host_count = HostsDownList.erase( host_address ); |
141 | ||
142 | BOOST_ASSERT( erased_host_count == 1 ); | |
f5ffc5df CH |
143 | |
144 | return true; | |
1266407a | 145 | } |
f5ffc5df CH |
146 | else |
147 | return false; | |
148 | ||
1266407a | 149 | } |
c1fff16a | 150 | |
72e54d1c | 151 | void LinkStatus::add_host_down( const string &host_address ) |
1266407a | 152 | { |
a4049623 | 153 | (void) HostsDownList.insert( host_address ); |
1266407a | 154 | } |
c1fff16a | 155 | |
72e54d1c | 156 | bool LinkStatus::exceeded_host_down_limit() const |
1266407a | 157 | { |
cf289c98 | 158 | int host_down_count = static_cast<int>( HostsDownList.size() ); |
6cfbd37c | 159 | |
a341119a | 160 | return ( host_down_count > HostsDownLimit ); |
ddf41c89 | 161 | } |
b279ae09 | 162 | |
72e54d1c | 163 | void LinkStatus::notify_link_up() |
b279ae09 | 164 | { |
72e54d1c | 165 | set_link_status( Status_Up ); |
b279ae09 | 166 | |
1634f2a1 GMF |
167 | // report the link status only if: it is up longer than a configured amount |
168 | // of time, and if we haven't reported the new status yet | |
f1bf3249 GMF |
169 | if ( is_link_up_enough_time() && can_report_link_status() ) |
170 | { | |
72e54d1c | 171 | BOOST_ASSERT( CurrentLinkStatus == Status_Up ); |
f1bf3249 GMF |
172 | BOOST_ASSERT( CurrentNotificationStatus == NotificationStatus_NotReported ); |
173 | ||
709ded82 | 174 | StatusNotifierCmd->set_token_value( |
f1bf3249 GMF |
175 | StatusNotifierCommand::StatusToken, |
176 | "up" | |
2a686bc0 | 177 | ); //lint !e534 |
f1bf3249 | 178 | |
f5ffc5df CH |
179 | GlobalLogger.notice() << "Status (" << HostsDownList.size() |
180 | << "/" << HostsDownLimit << " down): report link up" << endl; | |
709ded82 | 181 | bool executed = StatusNotifierCmd->execute(); |
f1bf3249 | 182 | |
2a686bc0 | 183 | if ( executed ) |
a4049623 GMF |
184 | { |
185 | CurrentNotificationStatus = NotificationStatus_Reported; | |
186 | } | |
f1bf3249 | 187 | } |
b279ae09 GMF |
188 | } |
189 | ||
72e54d1c | 190 | void LinkStatus::notify_link_down() |
b279ae09 | 191 | { |
72e54d1c | 192 | set_link_status( Status_Down ); |
f1bf3249 | 193 | |
1634f2a1 GMF |
194 | // report the link status only if: it is down longer than a configured amount |
195 | // of time, and if we haven't reported the new status yet | |
196 | if ( is_link_down_enough_time() && can_report_link_status() ) | |
f1bf3249 | 197 | { |
72e54d1c | 198 | BOOST_ASSERT( CurrentLinkStatus == Status_Down ); |
f1bf3249 | 199 | BOOST_ASSERT( CurrentNotificationStatus == NotificationStatus_NotReported ); |
b279ae09 | 200 | |
f5ffc5df CH |
201 | GlobalLogger.notice() << "Status (" << HostsDownList.size() |
202 | << "/" << HostsDownLimit << " down): report link down" << endl; | |
709ded82 | 203 | StatusNotifierCmd->set_token_value( |
f1bf3249 GMF |
204 | StatusNotifierCommand::StatusToken, |
205 | "down" | |
2a686bc0 | 206 | ); //lint !e534 |
f1bf3249 | 207 | |
709ded82 | 208 | bool executed = StatusNotifierCmd->execute(); |
f1bf3249 | 209 | |
2a686bc0 | 210 | if ( executed ) |
a4049623 GMF |
211 | { |
212 | CurrentNotificationStatus = NotificationStatus_Reported; | |
213 | } | |
f1bf3249 GMF |
214 | } |
215 | } | |
216 | ||
72e54d1c | 217 | bool LinkStatus::is_link_up_enough_time() const |
f1bf3249 | 218 | { |
72e54d1c | 219 | if ( CurrentLinkStatus == Status_Up ) |
f1bf3249 GMF |
220 | { |
221 | ptime now = microsec_clock::universal_time(); | |
222 | long amount_time_link_is_up = (now - TimeLinkStatusChanged).total_seconds(); | |
223 | long link_up_interval_in_sec = LinkUpIntervalInMin * 60; | |
224 | ||
225 | if ( amount_time_link_is_up >= link_up_interval_in_sec ) | |
226 | { | |
227 | return true; | |
228 | } | |
229 | } | |
230 | ||
231 | return false; | |
232 | } | |
233 | ||
72e54d1c | 234 | bool LinkStatus::is_link_down_enough_time() const |
1634f2a1 | 235 | { |
72e54d1c | 236 | if ( CurrentLinkStatus == Status_Down ) |
1634f2a1 GMF |
237 | { |
238 | ptime now = microsec_clock::universal_time(); | |
239 | long amount_time_link_is_down = (now - TimeLinkStatusChanged).total_seconds(); | |
240 | long link_down_interval_in_sec = LinkDownIntervalInMin * 60; | |
241 | ||
242 | if ( amount_time_link_is_down >= link_down_interval_in_sec ) | |
243 | { | |
244 | return true; | |
245 | } | |
246 | } | |
247 | ||
248 | return false; | |
249 | } | |
250 | ||
72e54d1c | 251 | bool LinkStatus::can_report_link_status() const |
f1bf3249 GMF |
252 | { |
253 | return ( CurrentNotificationStatus == NotificationStatus_NotReported ); | |
254 | } | |
255 | ||
72e54d1c GMF |
256 | void LinkStatus::set_link_status( |
257 | const LinkStatus::Status new_link_status | |
f1bf3249 GMF |
258 | ) |
259 | { | |
260 | // only reset the control flags if the link status has changed | |
261 | if ( new_link_status != CurrentLinkStatus ) | |
262 | { | |
263 | CurrentLinkStatus = new_link_status; | |
264 | TimeLinkStatusChanged = microsec_clock::universal_time(); | |
265 | ||
266 | // have to report the link status change | |
267 | CurrentNotificationStatus = NotificationStatus_NotReported; | |
268 | } | |
b279ae09 | 269 | } |