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.
21 #include "host/pingrotate.h"
23 #include <logfunc.hpp>
25 #include <boost/bind.hpp>
26 #include <boost/foreach.hpp>
28 #include "boost_assert_handler.h"
29 #include "dns/dnsmaster.h"
30 #include "host/pingerfactory.h"
33 using boost::function;
34 using boost::shared_ptr;
36 using I2n::Logger::GlobalLogger;
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
43 * @brief Parameterized constructor.
45 * @param io_serv The one @c io_service object that controls async processing
46 * @param network_interface The name of the network interface from where to
48 * @param destination_address The remote address to ping.
49 * @param destination_port The remote port to ping.
50 * @param protocol_list A list of protocols to be used to ping the
51 * host. The protocols will be used in the order they are in the list.
53 PingRotate::PingRotate(
54 const IoServiceItem io_serv,
55 const string &network_interface,
56 const string &destination_address,
57 const uint16_t destination_port,
58 const int resolved_ip_ttl_threshold,
59 const int ping_reply_timeout,
60 const PingProtocolList &protocol_list
63 NetworkInterfaceName( network_interface ),
65 DestinationAddress( destination_address ),
66 DestinationPort( destination_port ),
67 ResolvedIpTtlThreshold( resolved_ip_ttl_threshold ),
68 PingReplyTimeout( ping_reply_timeout ),
69 ProtocolRotate( protocol_list.size() ),
72 DnsResolutionFinished( true ),
75 BOOST_ASSERT( !network_interface.empty() );
76 BOOST_ASSERT( !destination_address.empty() );
77 BOOST_ASSERT( 0 < destination_port );
78 BOOST_ASSERT( 0 < protocol_list.size() );
80 // fill circular buffer with protocols
81 BOOST_FOREACH( const PingProtocol &prot, protocol_list )
82 ProtocolRotate.push_back(prot);
90 PingRotate::~PingRotate()
95 * @brief Ping a destination address from an available local source.
97 * @param done_handler Done handler will be called on successful ping or timeout.
101 void PingRotate::ping( function<void(bool)> ping_done_callback )
103 BOOST_ASSERT( ( 0 < DestinationPort ) && ( DestinationPort < numeric_limits<uint16_t>::max() ) );
105 set_ping_done_callback( ping_done_callback );
107 update_ping_protocol();
113 void PingRotate::try_to_ping()
117 GlobalLogger.info() << "PingRotate: not pinging yet (not requested to)";
120 else if ( !DnsResolutionFinished )
122 GlobalLogger.info() << "PingRotate: not pinging yet (DNS not finished)";
126 GlobalLogger.info() << "PingRotate: start ping";
128 string destination_ip = Resolver->get_next_ip().get_ip().to_string();
129 // TODO: pinger will probably re-create IP from this
130 // --> change pingers to accept ip::address
135 boost::bind(&PingRotate::ping_done_handler, this, _1)
139 void PingRotate::stop_pinging()
141 Ping->stop_pinging();
144 void PingRotate::start_resolving_ping_address() //lint !e1762
146 DnsResolutionFinished = false;
147 Resolver->async_resolve( boost::bind(&PingRotate::dns_resolve_callback,
151 int PingRotate::get_resolved_ip_count() const
153 return Resolver->get_resolved_ip_count();
156 bool PingRotate::have_up_to_date_ip() const
158 return Resolver->have_up_to_date_ip();
161 void PingRotate::set_ping_done_callback( function<void(bool)> ping_done_callback )
163 PingDoneCallback = ping_done_callback;
166 void PingRotate::ping_done_handler( bool ping_success ) const
168 PingDoneCallback( ping_success );
171 void PingRotate::init_ping_protocol()
173 get_next_ping_protocol();
176 void PingRotate::update_ping_protocol()
178 if ( can_change_ping_protocol() )
180 get_next_ping_protocol();
184 void PingRotate::get_next_ping_protocol()
186 PingProtocol ping_protocol = ProtocolRotate.front();
187 ProtocolRotate.pop_front();
188 ProtocolRotate.push_back(ping_protocol);
190 Ping = PingerFactory::createPinger( ping_protocol, IoService, NetworkInterfaceName, PingReplyTimeout );
192 update_dns_resolver( ping_protocol );
195 bool PingRotate::can_change_ping_protocol() const
197 // TODO can_change_ping_protocol() and get_next_ping_protocol() may be implemented in a Algorithm
198 // class that can be exchanged in this class to provide an algorithm neutral class
202 void PingRotate::update_dns_resolver( PingProtocol current_protocol )
204 // DNS master caches created resolvers and resolved IPs, so this will
205 // probably just return an existing resolver with already resolved IPs for
206 // requested protocol ( ICMP/TCP is ignored, only IPv4/v6 is important)
207 Resolver = DnsMaster::get_instance()->get_resolver_for(DestinationAddress,
209 // start resolving if no ips available
210 if ( !Resolver->have_up_to_date_ip() )
211 start_resolving_ping_address();
214 void PingRotate::dns_resolve_callback(const bool was_success,
215 const int recursion_count)
217 GlobalLogger.info() << "PingRotate: dns resolution finished "
218 << "with success = " << was_success << " "
219 << "and recursion_count = " << recursion_count;
220 throw std::runtime_error("Only debugging DNS -- exit by error");
221 if (DnsResolutionFinished)
222 { // there were probably several calls to async_resolve before it could
223 // finish --> ignore this callback
224 GlobalLogger.info() << "PingRotate: dns resolve callback called "
225 << "but dns is marked as finished already - ignore";
230 DnsResolutionFinished = true;