2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
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.
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.
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.
20 #include "link/linkstatus.h"
24 #include <logfunc.hpp>
26 #include "dns/dnsmaster.h"
28 #include "boost_assert_handler.h"
31 using boost::posix_time::microsec_clock;
32 using boost::posix_time::ptime;
33 using I2n::Logger::GlobalLogger;
35 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
40 * @brief Creates a link status object.
42 * @param hosts_down_limit The maximum amount of different hosts that can be
43 * down before the system take any action.
44 * @param link_up_interval_in_min The amount of time required to the link to
45 * stay up before notify.
46 * @param link_down_interval_in_min The amount of time required to the link to
47 * stay down before notify.
48 * @param status_notifier_cmd The command used to notify about link status
51 LinkStatus::LinkStatus(
52 const int hosts_down_limit,
53 const int link_up_interval_in_min,
54 const int link_down_interval_in_min,
55 const string &status_notifier_cmd
57 HostsDownLimit( hosts_down_limit ),
59 LinkUpIntervalInMin( link_up_interval_in_min ),
60 LinkDownIntervalInMin( link_down_interval_in_min ),
61 CurrentLinkStatus( Status_Down ),
62 CurrentNotificationStatus( NotificationStatus_NotReported ),
63 TimeLinkStatusChanged( microsec_clock::universal_time() ),
64 StatusNotifierCmd( new StatusNotifierCommand( status_notifier_cmd ) )
66 BOOST_ASSERT( 0 <= hosts_down_limit );
67 BOOST_ASSERT( 0 <= link_up_interval_in_min );
68 BOOST_ASSERT( 0 <= link_down_interval_in_min );
71 LinkStatus::~LinkStatus()
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.
81 * @param host_address the DNS/IP address of the host that is up.
83 void LinkStatus::notify_host_up( const string &host_address )
85 BOOST_ASSERT( !host_address.empty() );
87 bool has_changed = add_host_up( host_address );
90 GlobalLogger.notice() << "Status (" << HostsDownList.size()
91 << " down, limit=" << HostsDownLimit << "): now up again is "
92 << DnsMaster::get_cname_chain_str(host_address) << endl;
93 else // less important so log only at info level
94 GlobalLogger.info() << "Status (" << HostsDownList.size()
95 << " down, limit=" << HostsDownLimit << "): still up is "
96 << DnsMaster::get_cname_chain_str(host_address) << endl;
98 if ( !exceeded_host_down_limit() )
103 // removed from the list?
104 BOOST_ASSERT( HostsDownList.count( host_address ) == 0 );
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.
113 * @param host_address The DNS/IP address of the host that is down.
115 void LinkStatus::notify_host_down( const string &host_address )
117 BOOST_ASSERT( !host_address.empty() );
119 add_host_down( host_address );
121 // report this always at notice level
122 GlobalLogger.notice() << "Status (" << HostsDownList.size()
123 << " down, limit=" << HostsDownLimit << "): down is "
124 << DnsMaster::get_cname_chain_str(host_address) << endl;
126 if ( exceeded_host_down_limit() )
131 // inserted in the list?
132 BOOST_ASSERT( HostsDownList.count( host_address ) == 1 );
135 // returns true if this did change something (i.e. host had been down)
136 bool LinkStatus::add_host_up( const string &host_address )
138 if ( HostsDownList.count( host_address ) > 0 )
140 size_t erased_host_count = HostsDownList.erase( host_address );
142 BOOST_ASSERT( erased_host_count == 1 );
151 void LinkStatus::add_host_down( const string &host_address )
153 (void) HostsDownList.insert( host_address );
156 bool LinkStatus::exceeded_host_down_limit() const
158 int host_down_count = static_cast<int>( HostsDownList.size() );
160 return ( host_down_count > HostsDownLimit );
163 void LinkStatus::notify_link_up()
165 set_link_status( Status_Up );
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
169 if ( is_link_up_enough_time() && can_report_link_status() )
171 BOOST_ASSERT( CurrentLinkStatus == Status_Up );
172 BOOST_ASSERT( CurrentNotificationStatus == NotificationStatus_NotReported );
174 StatusNotifierCmd->set_token_value(
175 StatusNotifierCommand::StatusToken,
179 GlobalLogger.notice() << "Status (" << HostsDownList.size()
180 << " down, limit=" << HostsDownLimit << "): report link up" << endl;
181 bool executed = StatusNotifierCmd->execute();
185 CurrentNotificationStatus = NotificationStatus_Reported;
190 void LinkStatus::notify_link_down()
192 set_link_status( Status_Down );
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() )
198 BOOST_ASSERT( CurrentLinkStatus == Status_Down );
199 BOOST_ASSERT( CurrentNotificationStatus == NotificationStatus_NotReported );
201 GlobalLogger.notice() << "Status (" << HostsDownList.size()
202 << " down, limit=" << HostsDownLimit << "): report link down"
204 StatusNotifierCmd->set_token_value(
205 StatusNotifierCommand::StatusToken,
209 bool executed = StatusNotifierCmd->execute();
213 CurrentNotificationStatus = NotificationStatus_Reported;
218 bool LinkStatus::is_link_up_enough_time() const
220 if ( CurrentLinkStatus == Status_Up )
222 ptime now = microsec_clock::universal_time();
223 long amount_time_link_is_up = (now - TimeLinkStatusChanged).total_seconds();
224 long link_up_interval_in_sec = LinkUpIntervalInMin * 60;
226 if ( amount_time_link_is_up >= link_up_interval_in_sec )
235 bool LinkStatus::is_link_down_enough_time() const
237 if ( CurrentLinkStatus == Status_Down )
239 ptime now = microsec_clock::universal_time();
240 long amount_time_link_is_down = (now - TimeLinkStatusChanged).total_seconds();
241 long link_down_interval_in_sec = LinkDownIntervalInMin * 60;
243 if ( amount_time_link_is_down >= link_down_interval_in_sec )
252 bool LinkStatus::can_report_link_status() const
254 return ( CurrentNotificationStatus == NotificationStatus_NotReported );
257 void LinkStatus::set_link_status(
258 const LinkStatus::Status new_link_status
261 // only reset the control flags if the link status has changed
262 if ( new_link_status != CurrentLinkStatus )
264 CurrentLinkStatus = new_link_status;
265 TimeLinkStatusChanged = microsec_clock::universal_time();
267 // have to report the link status change
268 CurrentNotificationStatus = NotificationStatus_NotReported;