Simplifying Network Interface class and using more Boost.Asio objects
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sat, 12 Nov 2011 03:01:50 +0000 (01:01 -0200)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sat, 12 Nov 2011 03:01:50 +0000 (01:01 -0200)
src/host/networkinterface.hpp
src/icmp/icmppinger.h
src/tcp/tcppinger.h

index f50fd92..09c16d2 100644 (file)
 
 #include <logfunc.hpp>
 
+#include "host/networkinterfacelist.h"
+
+typedef const struct sockaddr* const_sockaddr_ptr_t;
+typedef const struct sockaddr_in* const_sockaddr_in_ptr_t;
+typedef const struct sockaddr_in6* const_sockaddr_in6_ptr_t;
+
 //-----------------------------------------------------------------------------
 // NetworkInterface
 //-----------------------------------------------------------------------------
@@ -48,7 +54,7 @@
 /**
  * @brief This class represents a local network interface.
  */
-template<typename SocketType>
+template<typename SocketType, typename Protocol>
 class NetworkInterface
 {
 public:
@@ -62,7 +68,9 @@ public:
 
     std::string get_name() const;
 
-    boost::asio::ip::address get_address(bool is_ip4) const;
+    boost::asio::ip::address get_address( Protocol protocol ) const;
+
+    const uint8_t* get_address_bytes( const_sockaddr_ptr_t ifa_addr ) const;
 
 private:
     /// The network interface name which the socket is attached
@@ -77,8 +85,8 @@ private:
 // NetworkInterface
 //-----------------------------------------------------------------------------
 
-template<typename SocketType>
-NetworkInterface<SocketType>::NetworkInterface(
+template<typename SocketType, typename Protocol>
+NetworkInterface<SocketType, Protocol>::NetworkInterface(
         const std::string &nic_name,
         SocketType &boost_socket
 ) :
@@ -95,8 +103,8 @@ NetworkInterface<SocketType>::NetworkInterface(
  *
  * @return true if the bind was successfully, and false if the bind failed.
  */
-template<typename SocketType>
-bool NetworkInterface<SocketType>::bind()
+template<typename SocketType, typename Protocol>
+bool NetworkInterface<SocketType, Protocol>::bind()
 {
     BOOST_ASSERT( !Name.empty() );
 
@@ -122,107 +130,88 @@ bool NetworkInterface<SocketType>::bind()
  *
  * @return A string representing the name of the network interface.
  */
-template<typename SocketType>
-std::string NetworkInterface<SocketType>::get_name() const
+template<typename SocketType, typename Protocol>
+std::string NetworkInterface<SocketType, Protocol>::get_name() const
 {
+    BOOST_ASSERT( !Name.empty() );
+
     return Name;
 }
 
-#include <iostream>
-
 /**
  * @brief This method gets the local address of network interface.
  *
- * @return The integer IPv4 representing the local address of the network
- * interface.
+ * @return The @c boost::asio::ip::address representing the local address of
+ * the network interface.
  */
-template<typename SocketType>
-boost::asio::ip::address NetworkInterface<SocketType>::get_address(bool is_ip4) const
+template<typename SocketType, typename Protocol>
+boost::asio::ip::address NetworkInterface<SocketType, Protocol>::get_address(
+        Protocol protocol
+) const
 {
-#if 0
-    struct ifreq ifr;
-    memset( &ifr, 0, sizeof(ifr) );
-
-    // make sure the ifr.ifr_name has enough room to receive the network
-    // interface name
-    size_t network_interface_name_limit = sizeof(ifr.ifr_name);
-    if ( network_interface_name_limit <= Name.size() )
-    {
-        I2n::Logger::GlobalLogger.error()
-            << "Error: network interface name truncated" << std::endl;
-        return 0;
-    }
+    BOOST_ASSERT( (protocol.family() == PF_INET) || (protocol.family() == PF_INET6) );
 
-    strncpy( ifr.ifr_name, Name.c_str(), network_interface_name_limit );
-    ifr.ifr_addr.sa_family = AF_INET6; // TODO change to AF_INET6 when IPv6 -> NAO FUNCIONOU, USAR O addr6.cpp
+    NetworkInterfaceList nic_list;
 
-    int ioctl_resp = ioctl( Socket.native(), SIOCGIFADDR, &ifr );
-    if ( ioctl_resp != 0)
+    const sa_family_t addr_type = static_cast<sa_family_t>( protocol.family() );
+    const struct ifaddrs *ifa_entry = nic_list.find_interface( get_name(), addr_type );
+    if ( ifa_entry == NULL )
     {
-        I2n::Logger::GlobalLogger.error()
-            << "Error: could not retrieve IP address from network interface"
-            << std::endl;
-        return 0;
+        return boost::asio::ip::address();
     }
 
-    const sockaddr_in *source_sockaddr = reinterpret_cast<const sockaddr_in *>( &ifr.ifr_addr );
-    uint32_t source_ipv4_address = htonl( source_sockaddr->sin_addr.s_addr );
-
-    std::cout << source_ipv4_address << std::endl;
-
-    return source_ipv4_address;
-#endif
-
-    struct ifaddrs *ifa_first = NULL;
-    struct ifaddrs *ifa_current = NULL;
-    int rc = 0;
-    char addr_string[ INET6_ADDRSTRLEN ];
-
-    rc = getifaddrs( &ifa_first );
-    if ( rc == 0 )
+    const uint8_t *addr_bytes = get_address_bytes( ifa_entry->ifa_addr );
+    if ( addr_bytes != NULL )
     {
-        for ( ifa_current = ifa_first; ifa_current != NULL; ifa_current = ifa_current->ifa_next )
+        BOOST_ASSERT( ifa_entry->ifa_addr->sa_family == addr_type );
+
+        char addr_buffer_string[ INET6_ADDRSTRLEN ];
+        volatile const char *addr_ret_string = inet_ntop( addr_type, addr_bytes, addr_buffer_string, sizeof(addr_buffer_string) );
+        if ( addr_ret_string != NULL )
         {
-            if ( ifa_current->ifa_addr->sa_data == NULL)
+            if ( PF_INET == addr_type )
             {
-                continue;
+                return boost::asio::ip::address_v4::from_string( std::string( addr_buffer_string ) );
             }
-
-            char *interface_name = ifa_current->ifa_name;
-            if ( Name == interface_name )
+            else if ( PF_INET6 == addr_type )
             {
-                sa_family_t addr_type = ifa_current->ifa_addr->sa_family;
-                void *addr_bytes = NULL;
-
-                if ( AF_INET == addr_type )
-                {
-                    addr_bytes = &((struct sockaddr_in *) ifa_current->ifa_addr)->sin_addr;
-                }
-                else if ( AF_INET6 == addr_type )
-                {
-                    addr_bytes = &((struct sockaddr_in6 *) ifa_current->ifa_addr)->sin6_addr;
-                }
-
-                if ( addr_bytes != NULL )
-                {
-                    const char *a = inet_ntop( addr_type, addr_bytes, addr_string, sizeof(addr_string) );
-                    if ( a != NULL )
-                    {
-                        if ( AF_INET == addr_type )
-                        {
-                            return boost::asio::ip::address_v4::from_string( std::string( a ) );
-                        }
-                        else if ( AF_INET6 == addr_type )
-                        {
-                            return boost::asio::ip::address_v6::from_string( std::string( a ) );
-                        }
-                    }
-                }
+                return boost::asio::ip::address_v6::from_string( std::string( addr_buffer_string ) );
             }
         }
     }
 
-    freeifaddrs( ifa_first );
+    return boost::asio::ip::address();
+}
+
+/**
+ * @brief Converts @c sockaddr into a sequence of bytes.
+ *
+ * @param ifa_addr A @c sockaddr structure.
+ *
+ * @return A sequence of bytes representing the interface address.
+ */
+template<typename SocketType, typename Protocol>
+const uint8_t* NetworkInterface<SocketType, Protocol>::get_address_bytes(
+        const_sockaddr_ptr_t ifa_addr
+) const
+{
+    BOOST_ASSERT( ifa_addr != NULL );
+
+    sa_family_t addr_type = ifa_addr->sa_family;
+    const uint8_t *addr_bytes = NULL;
+
+    if ( PF_INET == addr_type )
+    {
+        const_sockaddr_in_ptr_t sockaddr = reinterpret_cast<const_sockaddr_in_ptr_t>( ifa_addr );
+        addr_bytes = reinterpret_cast<const uint8_t*>( & (sockaddr->sin_addr) );
+    }
+    else if ( PF_INET6 == addr_type )
+    {
+        const_sockaddr_in6_ptr_t sockaddr = reinterpret_cast<const_sockaddr_in6_ptr_t>( ifa_addr );
+        addr_bytes = reinterpret_cast<const uint8_t*>( & (sockaddr->sin6_addr) );
+    }
+
+    return addr_bytes;
 }
 
 #endif // NETWORK_INTERFACE_HPP
index baeaf37..57b5edb 100644 (file)
@@ -63,7 +63,7 @@ private:
     /// The socket object
     boost::asio::ip::icmp::socket Socket;
     /// This object represents the network interface
-    NetworkInterface<boost::asio::ip::icmp::socket> NetInterface;
+    NetworkInterface<boost::asio::ip::icmp::socket, boost::asio::ip::icmp> NetInterface;
     /// The timer of ICMP packet receive, triggers the timeout to avoid infinite
     /// wait
     boost::asio::deadline_timer IcmpPacketReceiveTimer;
index 0fd46a1..f85fc15 100644 (file)
@@ -85,7 +85,7 @@ private:
     /// the socket object
     boost::asio::ip::tcp_raw_protocol::socket Socket;
     /// This object represents the network interface
-    NetworkInterface<boost::asio::ip::tcp_raw_protocol::socket> NetInterface;
+    NetworkInterface<boost::asio::ip::tcp_raw_protocol::socket, boost::asio::ip::tcp_raw_protocol> NetInterface;
     /// the timer of TCP segment receive, triggers the timeout to avoid infinite
     /// wait
     boost::asio::deadline_timer TcpSegmentReceiveTimer;