From: Guilherme Maciel Ferreira Date: Mon, 1 Aug 2011 00:12:48 +0000 (-0300) Subject: Retrieve the local IP address from the interface using the low level ioctl, plus... X-Git-Tag: v1.1^2~40 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=60d13f4f730ce305705b92c0b9c25e7869b5dd5f;p=pingcheck Retrieve the local IP address from the interface using the low level ioctl, plus some code enhancements --- diff --git a/src/tcp/tcppinger.cpp b/src/tcp/tcppinger.cpp index 8f4cd54..3b9b72c 100644 --- a/src/tcp/tcppinger.cpp +++ b/src/tcp/tcppinger.cpp @@ -19,6 +19,11 @@ on this file might be covered by the GNU General Public License. */ #include "tcp/tcppinger.h" +#include +#include +#include +#include + #include #include @@ -49,12 +54,13 @@ using I2n::Logger::GlobalLogger; 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 ), @@ -65,11 +71,11 @@ TcpPinger::TcpPinger( 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 @@ -108,17 +114,30 @@ void TcpPinger::ping( 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 ) @@ -143,11 +162,12 @@ void TcpPinger::start_send() ++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. @@ -195,14 +215,18 @@ TcpHeader TcpPinger::create_tcp_header( 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; } @@ -294,25 +318,27 @@ void TcpPinger::set_ping_status( TcpPinger::PingStatus ping_status ) * 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; } diff --git a/src/tcp/tcppinger.h b/src/tcp/tcppinger.h index 87c3ca3..3826681 100644 --- a/src/tcp/tcppinger.h +++ b/src/tcp/tcppinger.h @@ -43,7 +43,7 @@ class TcpPinger : public Pinger 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(); @@ -63,7 +63,7 @@ private: }; 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 ); @@ -86,7 +86,7 @@ private: 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: @@ -96,6 +96,8 @@ 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; @@ -107,7 +109,7 @@ private: 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