//-----------------------------------------------------------------------------
BoostPinger::BoostPinger(
- boost::asio::io_service &io_serv,
+ io_service &io_serv,
+ string source_network_interface,
const int echo_reply_timeout_in_sec
) :
IoService( io_serv ),
EchoReplyTimeoutInSec( echo_reply_timeout_in_sec ),
PingerStatus( PingStatus_NotSent )
{
+ BOOST_ASSERT( !source_network_interface.empty() );
+
+ if ( !select_source_network_interface( source_network_interface ) )
+ {
+ cerr << "Error: could not bind the socket with the local interface."
+ << ::strerror( errno ) << endl;
+ }
+
}
BoostPinger::~BoostPinger()
TimeSent = microsec_clock::universal_time();
- // Send the request.
string dest_address_string = DestinationEndpoint.address().to_string();
BOOST_ASSERT( !dest_address_string.empty() );
- const_buffers_1 data = request_buffer.data();
- size_t bytes_sent = Socket.send_to( data, DestinationEndpoint );
- if ( bytes_sent != buffer_size( data ) )
+ // Send the request
+ try
+ {
+ const_buffers_1 data = request_buffer.data();
+ size_t bytes_sent = Socket.send_to( data, DestinationEndpoint );
+ if ( bytes_sent != buffer_size( data ) )
+ {
+ cerr << "Error: fail sending ping data." << endl;
+ }
+ }
+ catch ( const exception &ex )
{
- cerr << "Error: fail sending ping data." << endl;
+ cerr << "Error: fail sending ping data. " << ex.what() << endl;
}
schedule_timeout_echo_reply();
IcmpHeader icmp_hdr = icmp_packet.get_icmp_header();
size_t bytes_received = bytes_transferred - ipv4_hdr.get_header_length();
- string source_address = ipv4_hdr.get_source_address().to_string();
+ string remote_address = ipv4_hdr.get_source_address().to_string();
int sequence_number = icmp_hdr.get_sequence_number();
int ttl = ipv4_hdr.get_time_to_live();
ptime now = microsec_clock::universal_time();
int time = (now - TimeSent).total_milliseconds();
cout << bytes_received << " bytes "
- << "from " << source_address
+ << "from " << remote_address
<< ": icmp_seq=" << sequence_number
<< " ttl=" << ttl
<< " time=" << time << " ms" << endl;
{
return static_cast<uint16_t> ( ::getpid() );
}
+
+/**
+ * Avoid the socket to drop to another network interface if the destination
+ * is unreachable through the binded interface. Packets are sent only from
+ * this interface.
+ *
+ * @param source_network_interface The network interface to bind the pinger.
+ *
+ * @return false if the bind failed.
+ */
+bool BoostPinger::select_source_network_interface(
+ const string &source_network_interface
+)
+{
+ BOOST_ASSERT( !source_network_interface.empty() );
+
+ int ret = ::setsockopt(
+ Socket.native(),
+ SOL_SOCKET,
+ SO_BINDTODEVICE,
+ source_network_interface.c_str(),
+ source_network_interface.size()
+ );
+ if ( ret == -1 )
+ {
+ return false;
+ }
+
+ return true;
+}
PingScheduler::PingScheduler(
boost::asio::io_service &io_serv,
+ const string &ping_interface,
const string &ping_address,
const long ping_interval_in_sec,
const int ping_fail_percentage_limit,
) :
IoService( io_serv ),
+ LocalNetworkInterfaceName( ping_interface ),
Timer( io_serv ),
TimeSentLastPing( microsec_clock::universal_time() ),
PingIntervalInSec( ping_interval_in_sec ),
io_service io_serv;
int echo_reply_timeout_in_sec = 5; // TODO configurable: this is the timeout to WAIT FOR the ping before considering a timeout
- BoostPinger pinger( io_serv, echo_reply_timeout_in_sec );
+ BoostPinger pinger(
+ io_serv,
+ LocalNetworkInterfaceName,
+ echo_reply_timeout_in_sec
+ );
return pinger.ping( destination_ip );
}
public:
PingScheduler(
boost::asio::io_service &io_serv,
+ const std::string &ping_interface,
const std::string &ping_address,
const long ping_interval_in_sec,
const int ping_fail_percentage_limit,
private:
boost::asio::io_service &IoService;
+ std::string LocalNetworkInterfaceName;
boost::asio::deadline_timer Timer;
boost::posix_time::ptime TimeSentLastPing;
PingInterval<long> PingIntervalInSec;