*/
#include "tcp/tcppinger.h"
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
#include <istream>
#include <ostream>
TcpPinger::TcpPinger(
io_service &io_serv,
- const string &source_network_interface,
+ const string &source_network_interface_name,
const int echo_reply_timeout_in_sec
) :
IoService( io_serv ),
DestinationEndpoint(),
Socket( IoService, tcp_raw_protocol::v4() ),
+ SourceNetworkInterfaceName( source_network_interface_name ),
TcpSegmentReceiveTimer( IoService ),
Identifier( 0 ),
SequenceNumber( 0 ),
PingerStatus( PingStatus_NotSent ),
PingDoneCallback()
{
- if ( !source_network_interface.empty() &&
- !select_source_network_interface( source_network_interface ) )
+ if ( !source_network_interface_name.empty() &&
+ !select_source_network_interface( source_network_interface_name ) )
{
GlobalLogger.error() << "Error: could not bind the socket "
- "with the local interface." << ::strerror( errno ) << endl;
+ "with the local interface. " << ::strerror( errno ) << endl;
}
// Create "unique" identifier
start_receive();
}
-uint32_t TcpPinger::get_source_address() const
+uint32_t TcpPinger::get_source_address()
{
- return 0xC0A80166; // TODO 192.168.1.102
+ struct ifreq ifr;
+ memset( &ifr, 0, sizeof(ifr) );
+ strcpy( ifr.ifr_name, SourceNetworkInterfaceName.c_str() );
+ ifr.ifr_addr.sa_family = AF_INET;
+ int ioctl_resp = ioctl( Socket.native(), SIOCGIFADDR, &ifr );
+ if ( ioctl_resp == 0)
+ {
+ return ((uint32_t) ifr.ifr_addr.sa_data[2] & 0xFF) << 24 |
+ ((uint32_t) ifr.ifr_addr.sa_data[3] & 0xFF) << 16 |
+ ((uint32_t) ifr.ifr_addr.sa_data[4] & 0xFF) << 8 |
+ ((uint32_t) ifr.ifr_addr.sa_data[5] & 0xFF);
+ }
+
+ return 0;
}
uint32_t TcpPinger::get_destination_address() const
{
- return ((unsigned int) DestinationEndpoint.data()->sa_data[2] & 0xFF) << 24 |
- ((unsigned int) DestinationEndpoint.data()->sa_data[3] & 0xFF) << 16 |
- ((unsigned int) DestinationEndpoint.data()->sa_data[4] & 0xFF) << 8 |
- ((unsigned int) DestinationEndpoint.data()->sa_data[5] & 0xFF);
+ return ((uint32_t) DestinationEndpoint.data()->sa_data[2] & 0xFF) << 24 |
+ ((uint32_t) DestinationEndpoint.data()->sa_data[3] & 0xFF) << 16 |
+ ((uint32_t) DestinationEndpoint.data()->sa_data[4] & 0xFF) << 8 |
+ ((uint32_t) DestinationEndpoint.data()->sa_data[5] & 0xFF);
}
void TcpPinger::set_destination_endpoint( const string &destination_ip )
++SequenceNumber
);
- // TODO isolate this part, so it can change without break the rest of the code
- uint32_t src_addr = get_source_address();
- uint32_t dest_addr = get_destination_address();
+ uint32_t source_address = get_source_address();
+ uint32_t destination_address = get_destination_address();
- uint16_t cksum = tcp_header.calculate_tcp_checksum( src_addr, dest_addr, NULL, 0 );
+ uint16_t cksum = tcp_header.calculate_tcp_checksum(
+ source_address, destination_address, NULL, 0
+ );
tcp_header.checksum( cksum );
// Encode the request packet.
const uint16_t sequence_number
) const
{
+ // (5 words of 32 bits = 5 * 4 bytes = 20 bytes)
+ const uint8_t header_size_in_words = 5; // size in units of 32 bits
+ const uint16_t window_size_in_octets = 32768;
+
// Create an TCP header for an ACK request.
TcpHeader tcp_header;
tcp_header.source_port( source_port ); // assign an random ephemeral port number
tcp_header.destination_port( destination_port );
tcp_header.sequence_number( sequence_number );
- tcp_header.header_length( 5 ); // header size in units of 32 bits (5 words of 32 bits = 5 * 4 bytes = 20 bytes)
+ tcp_header.header_length( header_size_in_words );
tcp_header.acknowledgment( true );
- tcp_header.window_size( 32768 ); // window size
+ tcp_header.window_size( window_size_in_octets ); // window size
return tcp_header;
}
* is unreachable through the binded interface. Packets are sent only from
* this interface.
*
- * @param source_network_interface The network interface to bind the pinger.
+ * @param source_network_interface_name The network interface to bind the pinger.
*
* @return false if the bind failed.
*/
bool TcpPinger::select_source_network_interface(
- const string &source_network_interface
+ const string &source_network_interface_name
)
{
- BOOST_ASSERT( !source_network_interface.empty() );
+ BOOST_ASSERT( !source_network_interface_name.empty() );
int ret = ::setsockopt(
Socket.native(),
SOL_SOCKET,
SO_BINDTODEVICE,
- source_network_interface.c_str(),
- source_network_interface.size()
+ source_network_interface_name.c_str(),
+ source_network_interface_name.size()
);
if ( ret == -1 )
{
+ GlobalLogger.error() << "Error: could not bind pinger to interface "
+ << source_network_interface_name << endl;
return false;
}
public:
TcpPinger(
boost::asio::io_service &io_service,
- const std::string &source_network_interface,
+ const std::string &source_network_interface_name,
const int echo_reply_timeout_in_sec
);
virtual ~TcpPinger();
};
private:
- uint32_t get_source_address() const;
+ uint32_t get_source_address();
uint32_t get_destination_address() const;
void set_destination_endpoint( const std::string &destination_ip );
void set_ping_status( TcpPinger::PingStatus ping_status );
bool select_source_network_interface(
- const std::string &source_network_interface
+ const std::string &source_network_interface_name
);
private:
boost::asio::ip::tcp_raw_protocol::endpoint DestinationEndpoint;
/// the socket object
boost::asio::ip::tcp_raw_protocol::socket Socket;
+ /// the network interface name which the socket is attached
+ std::string SourceNetworkInterfaceName;
/// the timer of TCP segment receive, triggers the timeout to avoid infinite
/// wait
boost::asio::deadline_timer TcpSegmentReceiveTimer;
boost::posix_time::ptime TimeSent;
/// the buffer where the data received will be placed
boost::asio::streambuf ReplyBuffer;
- /// Flag to indicate if we got a reply or not
+ /// flag to indicate if we got a reply or not
/// number of replies to the ICMP echo request
bool ReceivedReply;
/// the amount of time to wait for the reply