Interface name resultion using SIOCGIFADDR implemented

Signed-off-by: Martin Sustrik <sustrik@250bpm.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 95ee837..531f142 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -81,6 +81,11 @@
     add_definitions (-DSP_HAVE_IFADDRS)
 endif ()
 
+check_symbol_exists (SIOCGIFADDR sys/ioctl.h SP_HAVE_SIOCGIFADDR)
+if (SP_HAVE_SIOCGIFADDR)
+    add_definitions (-DSP_HAVE_SIOCGIFADDR)
+endif ()
+
 list (APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
 check_symbol_exists (accept4 sys/socket.h SP_HAVE_ACCEPT4)
 list (REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
@@ -113,6 +118,10 @@
 
 if (SP_HAVE_IFADDRS)
     add_definitions (-DSP_USE_IFADDRS)
+elseif (SP_HAVE_SIOCGIFADDR)
+    add_definitions (-DSP_USE_SIOCGIFADDR)
+else ()
+    add_definitions (-DSP_USE_LITERAL_IFADDR)
 endif ()
 
 #  Subdirectories to build.
diff --git a/src/utils/addr.c b/src/utils/addr.c
index 181bcbf..75a67c8 100644
--- a/src/utils/addr.c
+++ b/src/utils/addr.c
@@ -147,7 +147,60 @@
     return -ENODEV;
 }
 
+#endif
+
+#if defined SP_USE_SIOCGIFADDR
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+int sp_addr_parse_local (const char *addr, size_t addrlen, int flags,
+    struct sockaddr_storage *result, sp_socklen *resultlen)
+{
+    int rc;
+    int s;
+    struct ifreq req;
+
+    /*  Open the helper socket. */
+#ifdef SOCK_CLOEXEC
+    s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 #else
+    s = socket (AF_INET, SOCK_DGRAM, 0);
+#endif
+    errno_assert (s != -1);
+
+    /*  Create the interface name resolution request. */
+    if (sizeof (req.ifr_name) <= addrlen) {
+        rc = close (s);
+        errno_assert (rc == 0);
+        return -ENODEV;
+    }
+    memcpy (req.ifr_name, addr, addrlen);
+    req.ifr_name [addrlen] = 0;
+
+    /*  Execute the request. */
+    rc = ioctl (s, SIOCGIFADDR, (caddr_t) &req, sizeof (struct ifreq));
+    if (rc == -1) {
+        rc = close (s);
+        errno_assert (rc == 0);
+        return -ENODEV;
+    }
+
+    /*  Interface name resolution succeeded. Return the address to the user. */
+    /*  TODO: What about IPv6 addresses? */
+    sp_assert (req.ifr_addr.sa_family == AF_INET);
+    memcpy (result, (struct sockaddr_in*) &req.ifr_addr,
+        sizeof (struct sockaddr_in));
+    *resultlen = sizeof (struct sockaddr_in);
+    rc = close (s);
+    errno_assert (rc == 0);
+    return 0;
+}
+
+#endif
+
+#if defined SP_USE_LITERAL_IFADDR
 
 /*  The last resort case. If we haven't found any mechanism for turning
     NIC names into addresses, we'll try to resolve the string as an address