Bring aboard the Network Interface template class.
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sat, 20 Aug 2011 04:16:50 +0000 (01:16 -0300)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sat, 20 Aug 2011 04:16:50 +0000 (01:16 -0300)
- It is a template because it uses the generic socket type, to avoid inheritances.
- This template class hides much of the low level socket handling.

src/host/networkinterface.hpp [new file with mode: 0644]

diff --git a/src/host/networkinterface.hpp b/src/host/networkinterface.hpp
new file mode 100644 (file)
index 0000000..53b543d
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+ */
+
+#ifndef NETWORK_INTERFACE_HPP
+#define NETWORK_INTERFACE_HPP
+
+#include <errno.h>
+#include <net/if.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/asio/basic_socket.hpp>
+#include <boost/asio/basic_raw_socket.hpp>
+
+#include <logfunc.hpp>
+
+//-----------------------------------------------------------------------------
+// NetworkInterface
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief This class represents a local network interface.
+ */
+template<typename SocketType>
+class NetworkInterface
+{
+public:
+
+    NetworkInterface(
+            const std::string &nic_name,
+            SocketType &socket
+    );
+
+    bool bind();
+
+    std::string get_name() const;
+
+    uint32_t get_address();
+
+private:
+    /// The network interface name which the socket is attached
+    const std::string Name;
+    /// The native socket descriptor
+    SocketType &Socket;
+
+};
+
+
+//-----------------------------------------------------------------------------
+// NetworkInterface
+//-----------------------------------------------------------------------------
+
+template<typename SocketType>
+NetworkInterface<SocketType>::NetworkInterface(
+        const std::string &nic_name,
+        SocketType &socket
+) :
+    Name( nic_name ),
+    Socket( socket )
+{
+    BOOST_ASSERT( !nic_name.empty() );
+}
+
+/**
+ * @brief 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.
+ *
+ * @return true if the bind was successfully, and false if the bind failed.
+ */
+template<typename SocketType>
+bool NetworkInterface<SocketType>::bind()
+{
+    BOOST_ASSERT( !Name.empty() );
+
+    int ret = ::setsockopt(
+            Socket.native(),
+            SOL_SOCKET,
+            SO_BINDTODEVICE,
+            Name.c_str(),
+            Name.size()
+    );
+    if ( ret == -1 )
+    {
+        I2n::Logger::GlobalLogger.error()
+            << "Error: could not bind pinger to interface " << Name << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * @brief Get the network interface name.
+ *
+ * @return A string representing the name of the network interface.
+ */
+template<typename SocketType>
+std::string NetworkInterface<SocketType>::get_name() const
+{
+    return Name;
+}
+
+/**
+ * @brief This method gets the local address of network interface.
+ *
+ * @return The integer IP representing the local address of the network
+ * interface.
+ */
+template<typename SocketType>
+uint32_t NetworkInterface<SocketType>::get_address()
+{
+    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;
+    }
+
+    strncpy( ifr.ifr_name, Name.c_str(), network_interface_name_limit );
+    ifr.ifr_addr.sa_family = AF_INET; // TODO change to AF_INET6 when IPv6
+
+    int ioctl_resp = ioctl( Socket.native(), SIOCGIFADDR, &ifr );
+    if ( ioctl_resp != 0)
+    {
+        I2n::Logger::GlobalLogger.error()
+            << "Error: could not retrieve IP address from network interface"
+            << std::endl;
+        return 0;
+    }
+
+    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 );
+
+    return source_ipv4_address;
+}
+
+#endif // NETWORK_INTERFACE_HPP