[gssdp] client: Split get_host_ip



commit 5a232ff64cbb4bc1ae8bb6d6163f60124fb8f186
Author: Jens Georg <mail jensge org>
Date:   Tue Oct 11 22:32:26 2016 +0200

    client: Split get_host_ip
    
    Put the different network implementations in different files for better
    maintainability
    
    Signed-off-by: Jens Georg <mail jensge org>

 configure.ac                |    8 +
 libgssdp/Makefile.am        |    8 +-
 libgssdp/gssdp-client.c     |  602 +------------------------------------------
 libgssdp/gssdp-net-bionic.c |  320 +++++++++++++++++++++++
 libgssdp/gssdp-net-posix.c  |  208 +++++++++++++++
 libgssdp/gssdp-net-win32.c  |  236 +++++++++++++++++
 libgssdp/gssdp-net.h        |   65 +++++
 7 files changed, 857 insertions(+), 590 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index bfac21d..a5b7a7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -122,6 +122,14 @@ esac
 AC_MSG_RESULT([$target_android])
 AM_CONDITIONAL(TARGET_ANDROID, [test $target_android = yes])
 
+target_generic=no
+AS_IF([test "x$target_android" = "xno"],
+      [AS_IF([test "x$os_win32" = "xno"],
+             [target_generic="yes"])
+      ])
+
+AM_CONDITIONAL(TARGET_GENERIC, [test $target_generic = "yes"])
+
 dnl Check whether in_pktinfo is available
 AC_CHECK_TYPE(struct in_pktinfo,
               [
diff --git a/libgssdp/Makefile.am b/libgssdp/Makefile.am
index 0012ef8..b37e691 100644
--- a/libgssdp/Makefile.am
+++ b/libgssdp/Makefile.am
@@ -71,6 +71,7 @@ libgssdp_1_2_la_LDFLAGS = -version-info $(LTVERSION) $(WARN_LDFLAGS)
 libgssdp_1_2_la_SOURCES = $(introspection_sources)     \
                          gssdp-client-private.h        \
                          gssdp-protocol.h              \
+                         gssdp-net.h                   \
                          gssdp-socket-source.c         \
                          gssdp-socket-source.h         \
                          gssdp-socket-functions.c      \
@@ -85,15 +86,20 @@ endif
 libgssdp_1_2_la_LIBADD = $(LIBGSSDP_LIBS)
 
 if OS_WIN32
-
+libgssdp_1_2_la_SOURCES += gssdp-net-win32.c
 libgssdp_1_2_la_LIBADD += -lws2_32 -liphlpapi
 libgssdp_1_2_la_LDFLAGS += -no-undefined
 endif
 
 if TARGET_ANDROID
+libgssdp_1_2_la_SOURCES += gssdp-net-bionic.c
 libgssdp_1_2_la_LIBADD += -llog
 endif
 
+if TARGET_GENERIC
+libgssdp_1_2_la_SOURCES += gssdp-net-posix.c
+endif
+
 CLEANFILES = $(BUILT_SOURCES)
 
 -include $(INTROSPECTION_MAKEFILE)
diff --git a/libgssdp/gssdp-client.c b/libgssdp/gssdp-client.c
index f68e7ab..b123475 100644
--- a/libgssdp/gssdp-client.c
+++ b/libgssdp/gssdp-client.c
@@ -41,6 +41,7 @@
 #include "gssdp-error.h"
 #include "gssdp-socket-source.h"
 #include "gssdp-protocol.h"
+#include "gssdp-net.h"
 #include "gssdp-socket-functions.h"
 #ifdef HAVE_PKTINFO
 #include "gssdp-pktinfo-message.h"
@@ -48,53 +49,19 @@
 
 #include <sys/types.h>
 #include <glib.h>
-#ifndef G_OS_WIN32
-#include <sys/socket.h>
+#ifdef G_OS_WIN32
+#include <winsock2.h>
+#else
 #include <sys/utsname.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
-#ifdef __linux__
-/* headers for ARP */
-#include <net/if_arp.h>
-#include <sys/ioctl.h>
-#endif
-#else
-#define _WIN32_WINNT 0x502
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <iphlpapi.h>
-typedef int socklen_t;
-/* from the return value of inet_addr */
-typedef unsigned long in_addr_t;
 #endif
+
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifndef G_OS_WIN32
-#include <arpa/inet.h>
-#include <net/if.h>
-#ifndef __BIONIC__
-#include <ifaddrs.h>
-#else
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <stdlib.h>
-#endif
-#endif
-#include <libsoup/soup-headers.h>
 
-#ifdef HAVE_SIOCGIFINDEX
-#include <sys/ioctl.h>
-#endif
-
-#ifndef INET6_ADDRSTRLEN
-#define INET6_ADDRSTRLEN 46
-#endif
-
-#ifdef __BIONIC__
-#include <android/log.h>
-#endif
+#include <libsoup/soup-headers.h>
 
 /* Size of the buffer used for reading from the socket */
 #define BUF_SIZE 65536
@@ -106,16 +73,6 @@ static void
 gssdp_client_initable_iface_init (gpointer g_iface,
                                   gpointer iface_data);
 
-struct _GSSDPNetworkDevice {
-        char *iface_name;
-        char *host_ip;
-        GInetAddress *host_addr;
-        char *network;
-        struct sockaddr_in mask;
-        gint index;
-};
-typedef struct _GSSDPNetworkDevice GSSDPNetworkDevice;
-
 struct _GSSDPClientPrivate {
         char              *server_id;
 
@@ -191,10 +148,6 @@ gssdp_client_initable_init    (GInitable     *initable,
                                GCancellable  *cancellable,
                                GError       **error);
 
-static char *
-arp_lookup                    (GSSDPClient   *client,
-                               const char    *ip_address);
-
 static void
 gssdp_client_init (GSSDPClient *client)
 {
@@ -226,21 +179,8 @@ gssdp_client_initable_init (GInitable                   *initable,
         if (priv->initialized)
                 return TRUE;
 
-#ifdef G_OS_WIN32
-        WSADATA wsaData = {0};
-        if (WSAStartup (MAKEWORD (2,2), &wsaData) != 0) {
-                gchar *message;
-
-                message = g_win32_error_message (WSAGetLastError ());
-                g_set_error_literal (error,
-                                     GSSDP_ERROR,
-                                     GSSDP_ERROR_FAILED,
-                                     message);
-                g_free (message);
-
+        if (!gssdp_net_init (error))
                 return FALSE;
-        }
-#endif
 
         /* Make sure all network info is available to us */
         if (!init_network_info (client, &internal_error))
@@ -423,9 +363,8 @@ gssdp_client_finalize (GObject *object)
 {
         GSSDPClient *client = GSSDP_CLIENT (object);
         GSSDPClientPrivate *priv = gssdp_client_get_instance_private (client);
-#ifdef G_OS_WIN32
-        WSACleanup ();
-#endif
+
+        gssdp_net_shutdown ();
 
         g_clear_pointer (&priv->server_id, g_free);
         g_clear_pointer (&priv->device.iface_name, g_free);
@@ -780,7 +719,7 @@ gssdp_client_add_cache_entry (GSSDPClient  *client,
 
         priv = gssdp_client_get_instance_private (client);
 
-        hwaddr = arp_lookup (client, ip_address);
+        hwaddr = gssdp_net_arp_lookup (&priv->device, ip_address);
 
         if (hwaddr)
                 g_hash_table_insert (priv->user_agent_cache,
@@ -808,7 +747,7 @@ gssdp_client_guess_user_agent (GSSDPClient *client,
 
         priv = gssdp_client_get_instance_private (client);
 
-        hwaddr = arp_lookup (client, ip_address);
+        hwaddr = gssdp_net_arp_lookup (&priv->device, ip_address);
 
         if (hwaddr) {
                 const char *agent;
@@ -1361,479 +1300,6 @@ search_socket_source_cb (G_GNUC_UNUSED GIOChannel  *source,
         return socket_source_cb (priv->search_socket, client);
 }
 
-#ifdef G_OS_WIN32
-static gboolean
-is_primary_adapter (PIP_ADAPTER_ADDRESSES adapter)
-{
-        int family =
-                adapter->FirstUnicastAddress->Address.lpSockaddr->sa_family;
-
-        return !(adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK ||
-                 family == AF_INET6);
-}
-
-static gboolean
-extract_address_and_prefix (PIP_ADAPTER_UNICAST_ADDRESS  adapter,
-                            PIP_ADAPTER_PREFIX           prefix,
-                            char                        *iface,
-                            char                        *network) {
-        DWORD ret = 0;
-        DWORD len = INET6_ADDRSTRLEN;
-
-        ret = WSAAddressToStringA (adapter->Address.lpSockaddr,
-                                   adapter->Address.iSockaddrLength,
-                                   NULL,
-                                   iface,
-                                   &len);
-        if (ret != 0)
-                return FALSE;
-
-        if (prefix) {
-                ret = WSAAddressToStringA (prefix->Address.lpSockaddr,
-                                           prefix->Address.iSockaddrLength,
-                                           NULL,
-                                           network,
-                                           &len);
-                if (ret != 0)
-                        return FALSE;
-        } else if (strcmp (iface, "127.0.0.1"))
-                strcpy (network, "127.0.0.0");
-        else
-                return FALSE;
-
-        return TRUE;
-}
-#endif
-
-static int
-query_ifindex (const char *iface_name)
-{
-#if defined(HAVE_IFNAMETOINDEX)
-        return if_nametoindex (iface_name);
-
-#elif defined(HAVE_SIOCGIFINDEX)
-        int fd;
-        int result;
-        struct ifreq ifr;
-
-        fd = socket (AF_INET, SOCK_STREAM, 0);
-        if (fd < 0)
-                return -1;
-
-        memset (&ifr, 0, sizeof(struct ifreq));
-        strncpy (ifr.ifr_ifrn.ifrn_name, iface_name, IFNAMSIZ);
-
-        result = ioctl (fd, SIOCGIFINDEX, (char *)&ifr);
-        close (fd);
-
-        if (result == 0)
-                return ifr.ifr_ifindex;
-        else
-                return -1;
-#else
-        return -1;
-#endif
-}
-
-/*
- * Get the host IP for the specified interface. If no interface is specified,
- * it gets the IP of the first up & running interface and sets @interface
- * appropriately.
- */
-
-static gboolean
-get_host_ip (GSSDPNetworkDevice *device)
-{
-#ifdef G_OS_WIN32
-        GList *up_ifaces = NULL, *ifaceptr = NULL;
-        ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
-                      GAA_FLAG_SKIP_DNS_SERVER |
-                      GAA_FLAG_SKIP_MULTICAST;
-        DWORD size = 15360; /* Use 15k buffer initially as documented in MSDN */
-        DWORD ret;
-        PIP_ADAPTER_ADDRESSES adapters_addresses;
-        PIP_ADAPTER_ADDRESSES adapter;
-
-        do {
-                adapters_addresses = (PIP_ADAPTER_ADDRESSES) g_malloc0 (size);
-                ret = GetAdaptersAddresses (AF_UNSPEC,
-                                            flags,
-                                            NULL,
-                                            adapters_addresses,
-                                            &size);
-                if (ret == ERROR_BUFFER_OVERFLOW)
-                        g_free (adapters_addresses);
-        } while (ret == ERROR_BUFFER_OVERFLOW);
-
-        if (ret == ERROR_SUCCESS)
-                for (adapter = adapters_addresses;
-                     adapter != NULL;
-                     adapter = adapter->Next) {
-                        if (adapter->FirstUnicastAddress == NULL)
-                                continue;
-                        if (adapter->OperStatus != IfOperStatusUp)
-                                continue;
-                        /* skip Point-to-Point devices */
-                        if (adapter->IfType == IF_TYPE_PPP)
-                                continue;
-
-                        if (device->iface_name != NULL &&
-                            strcmp (device->iface_name, adapter->AdapterName) != 0)
-                                continue;
-
-                        /* I think that IPv6 is done via pseudo-adapters, so
-                         * that there are either IPv4 or IPv6 addresses defined
-                         * on the adapter.
-                         * Loopback-Devices and IPv6 go to the end of the list,
-                         * IPv4 to the front
-                         */
-                        if (is_primary_adapter (adapter))
-                                up_ifaces = g_list_prepend (up_ifaces, adapter);
-                        else
-                                up_ifaces = g_list_append (up_ifaces, adapter);
-                }
-
-        for (ifaceptr = up_ifaces;
-             ifaceptr != NULL;
-             ifaceptr = ifaceptr->next) {
-                char ip[INET6_ADDRSTRLEN];
-                char prefix[INET6_ADDRSTRLEN];
-                const char *p, *q;
-                PIP_ADAPTER_ADDRESSES adapter;
-                PIP_ADAPTER_UNICAST_ADDRESS address;
-                PIP_ADAPTER_PREFIX address_prefix;
-
-                p = NULL;
-
-                adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
-
-                for (address_prefix = adapter->FirstPrefix;
-                     address_prefix != NULL;
-                     address_prefix = address_prefix->Next)
-                        if (address_prefix->Address.lpSockaddr->sa_family == AF_INET)
-                                break;
-
-                if (address_prefix == NULL)
-                        continue;
-
-                for (address = adapter->FirstUnicastAddress;
-                     address != NULL;
-                     address = address->Next) {
-                        if (address->Address.lpSockaddr->sa_family != AF_INET)
-                                continue;
-
-                        if (extract_address_and_prefix (address,
-                                                        address_prefix,
-                                                        ip,
-                                                        prefix)) {
-                                p = ip;
-                                q = prefix;
-                        }
-
-                        if (p != NULL) {
-                                device->host_ip = g_strdup (p);
-                                /* This relies on the compiler doing an arithmetic
-                                 * shift here!
-                                 */
-                                gint32 mask = 0;
-                                if (address_prefix->PrefixLength > 0) {
-                                        mask = (gint32) 0x80000000;
-                                        mask >>= address_prefix->PrefixLength - 1;
-                                }
-                                device->mask.sin_family = AF_INET;
-                                device->mask.sin_port = 0;
-                                device->mask.sin_addr.s_addr = htonl ((guint32) mask);
-
-                                if (device->iface_name == NULL)
-                                        device->iface_name = g_strdup (adapter->AdapterName);
-                                if (device->network == NULL)
-                                        device->network = g_strdup (q);
-                                break;
-                        }
-                }
-
-                if (p != NULL)
-                        break;
-
-        }
-        g_list_free (up_ifaces);
-        g_free (adapters_addresses);
-
-        return TRUE;
-#elif defined(__BIONIC__)
-        struct      ifreq *ifaces = NULL;
-        struct      ifreq *iface = NULL;
-        struct      ifreq tmp_iface;
-        struct      ifconf ifconfigs;
-        struct      sockaddr_in *address, *netmask;
-        struct      in_addr net_address;
-        uint32_t    ip;
-        int         if_buf_size, sock, i, if_num;
-        GList       *if_ptr, *if_list = NULL;
-
-        if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
-                __android_log_write (ANDROID_LOG_WARN,
-                                     "gssdp",
-                                     "Couldn't create socket");
-                return FALSE;
-        }
-
-        /* Fill ifaces with the available interfaces
-         * we incrementally proceed in chunks of 4
-         * till getting the full list
-         */
-
-        if_buf_size = 0;
-        do {
-                if_buf_size += 4 * sizeof (struct ifreq);
-                ifaces = g_realloc (ifaces, if_buf_size);
-                ifconfigs.ifc_len = if_buf_size;
-                ifconfigs.ifc_buf = (char *) ifaces;
-
-                /* FIXME: IPv4 only. This ioctl only deals with AF_INET */
-                if (ioctl (sock, SIOCGIFCONF, &ifconfigs) == -1) {
-                        __android_log_print (ANDROID_LOG_WARN, "gssdp",
-                                "Couldn't get list of devices. Asked for: %d",
-                                if_buf_size / sizeof (struct ifreq));
-
-                        goto fail;
-                }
-
-        } while (ifconfigs.ifc_len >= if_buf_size);
-
-        if_num = ifconfigs.ifc_len / sizeof (struct ifreq);
-
-        if (!device->iface_name) {
-                __android_log_print (ANDROID_LOG_DEBUG, "gssdp",
-                        "Got list of %d interfaces. Looking for a suitable one",
-                        if_num);
-        } else {
-                __android_log_print (ANDROID_LOG_DEBUG, "gssdp",
-                        "List of %d interfaces ready. Now finding %s",
-                        if_num, device->iface_name);
-        }
-
-        /* Buildup prioritized interface list
-         */
-
-        for (i = 0; i < if_num; i++) {
-
-                address = (struct sockaddr_in *) &(ifaces[i].ifr_addr);
-
-                __android_log_print (ANDROID_LOG_DEBUG,
-                                     "gssdp",
-                                     "Trying interface: %s",
-                                     ifaces[i].ifr_name);
-
-                if (!address->sin_addr.s_addr) {
-                        __android_log_write (ANDROID_LOG_DEBUG, "gssdp",
-                                "No configured address. Discarding");
-                        continue;
-                }
-
-                memcpy (&tmp_iface, &ifaces[i], sizeof (struct ifreq));
-
-                if (ioctl (sock, SIOCGIFFLAGS, &tmp_iface) == -1) {
-                        __android_log_write (ANDROID_LOG_DEBUG, "gssdp",
-                                "Couldn't get flags. Discarding");
-                        continue;
-                }
-
-                /* If an specific interface query was passed over.. */
-                if (device->iface_name &&
-                    g_strcmp0 (device->iface_name, tmp_iface.ifr_name)) {
-                        continue;
-                } else if (!(tmp_iface.ifr_flags & IFF_UP) ||
-                           tmp_iface.ifr_flags & IFF_POINTOPOINT) {
-                        continue;
-                }
-
-                /* Prefer non loopback */
-                if (ifaces[i].ifr_flags & IFF_LOOPBACK)
-                        if_list = g_list_append (if_list, ifaces + i);
-                else
-                        if_list = g_list_prepend (if_list, ifaces + i);
-
-                if (device->iface_name)
-                        break;
-        }
-
-        if (!g_list_length (if_list)) {
-                __android_log_write (ANDROID_LOG_DEBUG,
-                                     "gssdp",
-                                     "No usable interfaces found");
-                goto fail;
-        }
-
-        /* Fill device with data from the first interface
-         * we can get complete config info for and return
-         */
-
-        for (if_ptr = if_list;
-             if_ptr != NULL;
-             if_ptr = g_list_next (if_ptr)) {
-
-                iface   = (struct ifreq *) if_ptr->data;
-                address = (struct sockaddr_in *) &(iface->ifr_addr);
-                netmask = (struct sockaddr_in *) &(iface->ifr_netmask);
-
-                device->host_ip = g_malloc0 (INET_ADDRSTRLEN);
-
-                if (inet_ntop (AF_INET, &(address->sin_addr),
-                        device->host_ip, INET_ADDRSTRLEN) == NULL) {
-
-                        __android_log_print (ANDROID_LOG_INFO,
-                                             "gssdp",
-                                             "Failed to get ip for: %s, %s",
-                                             iface->ifr_name,
-                                             strerror (errno));
-
-                        g_free (device->host_ip);
-                        device->host_ip = NULL;
-
-                        continue;
-                }
-
-                ip = address->sin_addr.s_addr;
-
-                if (ioctl (sock, SIOCGIFNETMASK, iface) == -1) {
-                        __android_log_write (ANDROID_LOG_DEBUG, "gssdp",
-                                "Couldn't get netmask. Discarding");
-                        g_free (device->host_ip);
-                        device->host_ip = NULL;
-
-                        continue;
-                }
-
-                memcpy (&device->mask, netmask, sizeof (struct sockaddr_in));
-
-                if (device->network == NULL) {
-                        device->network = g_malloc0 (INET_ADDRSTRLEN);
-
-                        net_address.s_addr = ip & netmask->sin_addr.s_addr;
-
-                        if (inet_ntop (AF_INET, &net_address,
-                            device->network, INET_ADDRSTRLEN) == NULL) {
-
-                                __android_log_print (ANDROID_LOG_WARN, "gssdp",
-                                        "Failed to get nw for: %s, %s",
-                                        iface->ifr_name, strerror (errno));
-
-                                g_clear_pointer (&device->host_ip, g_free);
-                                g_clear_pointer (&device->network, g_free);
-
-                                continue;
-                        }
-                }
-
-                if (!device->iface_name)
-                        device->iface_name = g_strdup (iface->ifr_name);
-
-                device->index = query_ifindex (device->iface_name);
-
-                goto success;
-
-        }
-
-        __android_log_write (ANDROID_LOG_WARN, "gssdp",
-                "Traversed whole list without finding a configured device");
-
-fail:
-        __android_log_write (ANDROID_LOG_WARN,
-                             "gssdp",
-                             "Failed to get configuration for device");
-        g_free (ifaces);
-        g_list_free (if_list);
-        close (sock);
-
-        return FALSE;
-success:
-        __android_log_print (ANDROID_LOG_DEBUG, "gssdp",
-                "Returned config params for device: %s ip: %s network: %s",
-                device->iface_name, device->host_ip, device->network);
-        g_free (ifaces);
-        g_list_free (if_list);
-        close (sock);
-        return TRUE;
-#else
-        struct ifaddrs *ifa_list, *ifa;
-        GList *up_ifaces, *ifaceptr;
-
-        up_ifaces = NULL;
-
-        if (getifaddrs (&ifa_list) != 0) {
-                g_warning ("Failed to retrieve list of network interfaces: %s",
-                           strerror (errno));
-
-                return FALSE;
-        }
-
-        for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
-                if (ifa->ifa_addr == NULL)
-                        continue;
-
-                if (device->iface_name &&
-                    !g_str_equal (device->iface_name, ifa->ifa_name))
-                        continue;
-                else if (!(ifa->ifa_flags & IFF_UP))
-                        continue;
-                else if ((ifa->ifa_flags & IFF_POINTOPOINT))
-                        continue;
-
-                /* Loopback and IPv6 interfaces go at the bottom on the list */
-                if ((ifa->ifa_flags & IFF_LOOPBACK) ||
-                    ifa->ifa_addr->sa_family == AF_INET6)
-                        up_ifaces = g_list_append (up_ifaces, ifa);
-                else
-                        up_ifaces = g_list_prepend (up_ifaces, ifa);
-        }
-
-        for (ifaceptr = up_ifaces;
-             ifaceptr != NULL;
-             ifaceptr = ifaceptr->next) {
-                char ip[INET6_ADDRSTRLEN];
-                char net[INET6_ADDRSTRLEN];
-                const char *p, *q;
-                struct sockaddr_in *s4, *s4_mask;
-                struct in_addr net_addr;
-                const guint8 *bytes;
-
-                ifa = ifaceptr->data;
-
-                if (ifa->ifa_addr->sa_family != AF_INET) {
-                        continue;
-                }
-
-                s4 = (struct sockaddr_in *) ifa->ifa_addr;
-                p = inet_ntop (AF_INET, &s4->sin_addr, ip, sizeof (ip));
-                device->host_ip = g_strdup (p);
-
-                bytes = (const guint8 *) &s4->sin_addr;
-                device->host_addr = g_inet_address_new_from_bytes
-                                        (bytes, G_SOCKET_FAMILY_IPV4);
-
-                s4_mask = (struct sockaddr_in *) ifa->ifa_netmask;
-                memcpy (&(device->mask), s4_mask, sizeof (struct sockaddr_in));
-                net_addr.s_addr = (in_addr_t) s4->sin_addr.s_addr &
-                                  (in_addr_t) s4_mask->sin_addr.s_addr;
-                q = inet_ntop (AF_INET, &net_addr, net, sizeof (net));
-
-                device->index = query_ifindex (ifa->ifa_name);
-
-                if (device->iface_name == NULL)
-                        device->iface_name = g_strdup (ifa->ifa_name);
-                if (device->network == NULL)
-                        device->network = g_strdup (q);
-                break;
-        }
-
-        g_list_free (up_ifaces);
-        freeifaddrs (ifa_list);
-
-        return TRUE;
-#endif
-}
-
 static gboolean
 init_network_info (GSSDPClient *client, GError **error)
 {
@@ -1846,7 +1312,7 @@ init_network_info (GSSDPClient *client, GError **error)
          */
         if (priv->device.iface_name == NULL ||
             priv->device.host_ip == NULL)
-                get_host_ip (&(priv->device));
+                gssdp_net_get_host_ip (&(priv->device));
         else {
                 /* Ugly. Ideally, get_host_ip needs to be run everytime, but
                  * it is currently to stupid so just query index here if we
@@ -1856,7 +1322,7 @@ init_network_info (GSSDPClient *client, GError **error)
                  * support this.
                  */
                 priv->device.index =
-                                query_ifindex (priv->device.iface_name);
+                        gssdp_net_query_ifindex (&priv->device);
         }
 
         if (priv->device.host_addr == NULL &&
@@ -1886,45 +1352,3 @@ init_network_info (GSSDPClient *client, GError **error)
         return ret;
 }
 
-static char *
-arp_lookup (GSSDPClient *client, const char *ip_address)
-{
-#if defined(__linux__)
-        GSSDPClientPrivate *priv = gssdp_client_get_instance_private (client);
-        struct arpreq req;
-        struct sockaddr_in *sin;
-        GSocket *socket;
-
-        memset (&req, 0, sizeof (req));
-
-        /* FIXME: Update when we support IPv6 properly */
-        sin = (struct sockaddr_in *) &req.arp_pa;
-        sin->sin_family = AF_INET;
-        sin->sin_addr.s_addr = inet_addr (ip_address);
-
-        strncpy (req.arp_dev,
-                 priv->device.iface_name,
-                 sizeof (req.arp_dev) - 1 /* nul terminator */);
-        socket = gssdp_socket_source_get_socket (priv->search_socket);
-
-        if (ioctl (g_socket_get_fd (socket), SIOCGARP, (caddr_t) &req) < 0) {
-                return NULL;
-        }
-
-        if (req.arp_flags & ATF_COM) {
-                unsigned char *buf = (unsigned char *) req.arp_ha.sa_data;
-
-                return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-                                        buf[0],
-                                        buf[1],
-                                        buf[2],
-                                        buf[3],
-                                        buf[4],
-                                        buf[5]);
-        }
-
-        return NULL;
-#else
-        return g_strdup (ip_address);
-#endif
-}
diff --git a/libgssdp/gssdp-net-bionic.c b/libgssdp/gssdp-net-bionic.c
new file mode 100644
index 0000000..ee070f6
--- /dev/null
+++ b/libgssdp/gssdp-net-bionic.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2016 Jens Georg <mail jensge org>
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include "gssdp-net.h"
+
+#include <glib.h>
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#ifdef __linux__
+#include <net/if_arp.h>
+#endif
+
+#include <android/log.h>
+
+gboolean
+gssdp_net_init (GError **error)
+{
+        return TRUE;
+}
+
+void
+gssdp_net_shutdown (void)
+{
+}
+
+int
+gssdp_net_query_ifindex (GSSDPNetworkDevice *device)
+{
+#if defined(HAVE_IFNAMETOINDEX)
+    return if_nametoindex (device->iface_name);
+
+#elif defined(HAVE_SIOCGIFINDEX)
+    int fd;
+    int result;
+    struct ifreq ifr;
+
+    fd = socket (AF_INET, SOCK_STREAM, 0);
+    if (fd < 0)
+        return -1;
+
+    memset (&ifr, 0, sizeof(struct ifreq));
+    strncpy (ifr.ifr_ifrn.ifrn_name, device->iface_name, IFNAMSIZ);
+
+    result = ioctl (fd, SIOCGIFINDEX, (char *)&ifr);
+    close (fd);
+
+    if (result == 0)
+        return ifr.ifr_ifindex;
+    else
+        return -1;
+#else
+    return -1;
+#endif
+}
+
+char *
+gssdp_net_arp_lookup (GSSDPNetworkDevice *device, const char *ip_address)
+{
+#if defined(__linux__)
+        struct arpreq req;
+        struct sockaddr_in *sin;
+        int fd = -1;
+
+        memset (&req, 0, sizeof (req));
+
+        /* FIXME: Update when we support IPv6 properly */
+        sin = (struct sockaddr_in *) &req.arp_pa;
+        sin->sin_family = AF_INET;
+        sin->sin_addr.s_addr = inet_addr (ip_address);
+
+        /* copy name, leave place for nul terminator */;
+        strncpy (req.arp_dev, device->iface_name, sizeof (req.arp_dev) - 1);
+
+        fd = socket (AF_INET, SOCK_STREAM, 0);
+        if (fd < 0)
+                return g_strdup (ip_address);
+
+        if (ioctl (fd, SIOCGARP, (caddr_t) &req) < 0) {
+                return NULL;
+        }
+        close (fd);
+
+        if (req.arp_flags & ATF_COM) {
+                unsigned char *buf = (unsigned char *) req.arp_ha.sa_data;
+
+                return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+                                        buf[0],
+                                        buf[1],
+                                        buf[2],
+                                        buf[3],
+                                        buf[4],
+                                        buf[5]);
+        }
+
+        return g_strdup (ip_address);
+#else
+        return g_strdup (ip_address);
+#endif
+}
+
+gboolean
+gssdp_net_get_host_ip (GSSDPNetworkDevice *device)
+{
+        struct      ifreq *ifaces = NULL;
+        struct      ifreq *iface = NULL;
+        struct      ifreq tmp_iface;
+        struct      ifconf ifconfigs;
+        struct      sockaddr_in *address, *netmask;
+        struct      in_addr net_address;
+        uint32_t    ip;
+        int         if_buf_size, sock, i, if_num;
+        GList       *if_ptr, *if_list = NULL;
+
+        if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+                __android_log_write (ANDROID_LOG_WARN,
+                                     "gssdp",
+                                     "Couldn't create socket");
+                return FALSE;
+        }
+
+        /* Fill ifaces with the available interfaces
+         * we incrementally proceed in chunks of 4
+         * till getting the full list
+         */
+
+        if_buf_size = 0;
+        do {
+                if_buf_size += 4 * sizeof (struct ifreq);
+                ifaces = g_realloc (ifaces, if_buf_size);
+                ifconfigs.ifc_len = if_buf_size;
+                ifconfigs.ifc_buf = (char *) ifaces;
+
+                /* FIXME: IPv4 only. This ioctl only deals with AF_INET */
+                if (ioctl (sock, SIOCGIFCONF, &ifconfigs) == -1) {
+                        __android_log_print (ANDROID_LOG_WARN, "gssdp",
+                                "Couldn't get list of devices. Asked for: %d",
+                                if_buf_size / sizeof (struct ifreq));
+
+                        goto fail;
+                }
+
+        } while (ifconfigs.ifc_len >= if_buf_size);
+
+        if_num = ifconfigs.ifc_len / sizeof (struct ifreq);
+
+        if (!device->iface_name) {
+                __android_log_print (ANDROID_LOG_DEBUG, "gssdp",
+                        "Got list of %d interfaces. Looking for a suitable one",
+                        if_num);
+        } else {
+                __android_log_print (ANDROID_LOG_DEBUG, "gssdp",
+                        "List of %d interfaces ready. Now finding %s",
+                        if_num, device->iface_name);
+        }
+
+        /* Buildup prioritized interface list
+         */
+
+        for (i = 0; i < if_num; i++) {
+
+                address = (struct sockaddr_in *) &(ifaces[i].ifr_addr);
+
+                __android_log_print (ANDROID_LOG_DEBUG,
+                                     "gssdp",
+                                     "Trying interface: %s",
+                                     ifaces[i].ifr_name);
+
+                if (!address->sin_addr.s_addr) {
+                        __android_log_write (ANDROID_LOG_DEBUG, "gssdp",
+                                "No configured address. Discarding");
+                        continue;
+                }
+
+                memcpy (&tmp_iface, &ifaces[i], sizeof (struct ifreq));
+
+                if (ioctl (sock, SIOCGIFFLAGS, &tmp_iface) == -1) {
+                        __android_log_write (ANDROID_LOG_DEBUG, "gssdp",
+                                "Couldn't get flags. Discarding");
+                        continue;
+                }
+
+                /* If an specific interface query was passed over.. */
+                if (device->iface_name &&
+                    g_strcmp0 (device->iface_name, tmp_iface.ifr_name)) {
+                        continue;
+                } else if (!(tmp_iface.ifr_flags & IFF_UP) ||
+                           tmp_iface.ifr_flags & IFF_POINTOPOINT) {
+                        continue;
+                }
+
+                /* Prefer non loopback */
+                if (ifaces[i].ifr_flags & IFF_LOOPBACK)
+                        if_list = g_list_append (if_list, ifaces + i);
+                else
+                        if_list = g_list_prepend (if_list, ifaces + i);
+
+                if (device->iface_name)
+                    break;
+        }
+
+        if (!g_list_length (if_list)) {
+                __android_log_write (ANDROID_LOG_DEBUG,
+                                     "gssdp",
+                                     "No usable interfaces found");
+                goto fail;
+        }
+
+        /* Fill device with data from the first interface
+         * we can get complete config info for and return
+         */
+
+        for (if_ptr = if_list; if_ptr != NULL;
+             if_ptr = g_list_next (if_ptr)) {
+
+                iface   = (struct ifreq *) if_ptr->data;
+                address = (struct sockaddr_in *) &(iface->ifr_addr);
+                netmask = (struct sockaddr_in *) &(iface->ifr_netmask);
+
+                device->host_ip = g_malloc0 (INET_ADDRSTRLEN);
+
+                if (inet_ntop (AF_INET, &(address->sin_addr),
+                        device->host_ip, INET_ADDRSTRLEN) == NULL) {
+
+                        __android_log_print (ANDROID_LOG_INFO,
+                                             "gssdp",
+                                             "Failed to get ip for: %s, %s",
+                                             iface->ifr_name,
+                                             strerror (errno));
+
+                        g_free (device->host_ip);
+                        device->host_ip = NULL;
+                        continue;
+                }
+
+                ip = address->sin_addr.s_addr;
+
+                if (ioctl (sock, SIOCGIFNETMASK, iface) == -1) {
+                        __android_log_write (ANDROID_LOG_DEBUG, "gssdp",
+                                "Couldn't get netmask. Discarding");
+                        g_free (device->host_ip);
+                        device->host_ip = NULL;
+                        continue;
+                }
+
+                memcpy (&device->mask, netmask, sizeof (struct sockaddr_in));
+
+                if (device->network == NULL) {
+                        device->network = g_malloc0 (INET_ADDRSTRLEN);
+
+                        net_address.s_addr = ip & netmask->sin_addr.s_addr;
+
+                        if (inet_ntop (AF_INET, &net_address,
+                            device->network, INET_ADDRSTRLEN) == NULL) {
+
+                                __android_log_print (ANDROID_LOG_WARN, "gssdp",
+                                        "Failed to get nw for: %s, %s",
+                                        iface->ifr_name, strerror (errno));
+
+                                g_free (device->host_ip);
+                                device->host_ip = NULL;
+                                g_free (device->network);
+                                device->network = NULL;
+                                continue;
+                        }
+                }
+
+                if (!device->iface_name)
+                    device->iface_name = g_strdup (iface->ifr_name);
+
+                goto success;
+
+        }
+
+        __android_log_write (ANDROID_LOG_WARN, "gssdp",
+                "Traversed whole list without finding a configured device");
+
+fail:
+        __android_log_write (ANDROID_LOG_WARN,
+                             "gssdp",
+                             "Failed to get configuration for device");
+        g_free (ifaces);
+        g_list_free (if_list);
+        close (sock);
+        return FALSE;
+success:
+        __android_log_print (ANDROID_LOG_DEBUG, "gssdp",
+                "Returned config params for device: %s ip: %s network: %s",
+                device->iface_name, device->host_ip, device->network);
+        g_free (ifaces);
+        g_list_free (if_list);
+        close (sock);
+        return TRUE;
+}
diff --git a/libgssdp/gssdp-net-posix.c b/libgssdp/gssdp-net-posix.c
new file mode 100644
index 0000000..dd5859e
--- /dev/null
+++ b/libgssdp/gssdp-net-posix.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 Jens Georg <mail jensge org>
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include "gssdp-net.h"
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __linux__
+#include <net/if_arp.h>
+#endif
+
+gboolean
+gssdp_net_init (GError **error)
+{
+        return TRUE;
+}
+
+void
+gssdp_net_shutdown (void)
+{
+}
+
+int
+gssdp_net_query_ifindex (GSSDPNetworkDevice *device)
+{
+#if defined(HAVE_IFNAMETOINDEX)
+    return if_nametoindex (device->iface_name);
+
+#elif defined(HAVE_SIOCGIFINDEX)
+    int fd;
+    int result;
+    struct ifreq ifr;
+
+    fd = socket (AF_INET, SOCK_STREAM, 0);
+    if (fd < 0)
+        return -1;
+
+    memset (&ifr, 0, sizeof(struct ifreq));
+    strncpy (ifr.ifr_ifrn.ifrn_name, device->iface_name, IFNAMSIZ);
+
+    result = ioctl (fd, SIOCGIFINDEX, (char *)&ifr);
+    close (fd);
+
+    if (result == 0)
+        return ifr.ifr_ifindex;
+    else
+        return -1;
+#else
+    return -1;
+#endif
+}
+
+char *
+gssdp_net_arp_lookup (GSSDPNetworkDevice *device, const char *ip_address)
+{
+#if defined(__linux__)
+        struct arpreq req;
+        struct sockaddr_in *sin;
+        int fd = -1;
+
+        memset (&req, 0, sizeof (req));
+
+        /* FIXME: Update when we support IPv6 properly */
+        sin = (struct sockaddr_in *) &req.arp_pa;
+        sin->sin_family = AF_INET;
+        sin->sin_addr.s_addr = inet_addr (ip_address);
+
+        /* copy name, leave place for nul terminator */;
+        strncpy (req.arp_dev, device->iface_name, sizeof (req.arp_dev) - 1);
+
+        fd = socket (AF_INET, SOCK_STREAM, 0);
+        if (fd < 0)
+                return g_strdup (ip_address);
+
+        if (ioctl (fd, SIOCGARP, (caddr_t) &req) < 0) {
+                return NULL;
+        }
+        close (fd);
+
+        if (req.arp_flags & ATF_COM) {
+                unsigned char *buf = (unsigned char *) req.arp_ha.sa_data;
+
+                return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+                                        buf[0],
+                                        buf[1],
+                                        buf[2],
+                                        buf[3],
+                                        buf[4],
+                                        buf[5]);
+        }
+
+        return g_strdup (ip_address);
+#else
+        return g_strdup (ip_address);
+#endif
+}
+
+gboolean
+gssdp_net_get_host_ip (GSSDPNetworkDevice *device)
+{
+        struct ifaddrs *ifa_list, *ifa;
+        GList *up_ifaces, *ifaceptr;
+
+        up_ifaces = NULL;
+
+        if (getifaddrs (&ifa_list) != 0) {
+                g_warning ("Failed to retrieve list of network interfaces: %s",
+                           strerror (errno));
+
+                return FALSE;
+        }
+
+        for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
+                if (ifa->ifa_addr == NULL)
+                        continue;
+
+                if (device->iface_name &&
+                    !g_str_equal (device->iface_name, ifa->ifa_name))
+                        continue;
+                else if (!(ifa->ifa_flags & IFF_UP))
+                        continue;
+                else if ((ifa->ifa_flags & IFF_POINTOPOINT))
+                        continue;
+
+                /* Loopback and IPv6 interfaces go at the bottom on the list */
+                if ((ifa->ifa_flags & IFF_LOOPBACK) ||
+                    ifa->ifa_addr->sa_family == AF_INET6)
+                        up_ifaces = g_list_append (up_ifaces, ifa);
+                else
+                        up_ifaces = g_list_prepend (up_ifaces, ifa);
+        }
+
+        for (ifaceptr = up_ifaces;
+             ifaceptr != NULL;
+             ifaceptr = ifaceptr->next) {
+                char ip[INET6_ADDRSTRLEN];
+                char net[INET6_ADDRSTRLEN];
+                const char *p, *q;
+                struct sockaddr_in *s4, *s4_mask;
+                struct in_addr net_addr;
+                const guint8 *bytes;
+
+                ifa = ifaceptr->data;
+
+                if (ifa->ifa_addr->sa_family != AF_INET) {
+                        continue;
+                }
+
+                s4 = (struct sockaddr_in *) ifa->ifa_addr;
+                p = inet_ntop (AF_INET, &s4->sin_addr, ip, sizeof (ip));
+                device->host_ip = g_strdup (p);
+
+                bytes = (const guint8 *) &s4->sin_addr;
+                device->host_addr = g_inet_address_new_from_bytes
+                                        (bytes, G_SOCKET_FAMILY_IPV4);
+
+                s4_mask = (struct sockaddr_in *) ifa->ifa_netmask;
+                memcpy (&(device->mask), s4_mask, sizeof (struct sockaddr_in));
+                net_addr.s_addr = (in_addr_t) s4->sin_addr.s_addr &
+                                  (in_addr_t) s4_mask->sin_addr.s_addr;
+                q = inet_ntop (AF_INET, &net_addr, net, sizeof (net));
+
+
+                if (device->iface_name == NULL)
+                        device->iface_name = g_strdup (ifa->ifa_name);
+                if (device->network == NULL)
+                        device->network = g_strdup (q);
+
+                device->index = gssdp_net_query_ifindex (device);
+                break;
+        }
+
+        g_list_free (up_ifaces);
+        freeifaddrs (ifa_list);
+
+        return TRUE;
+}
diff --git a/libgssdp/gssdp-net-win32.c b/libgssdp/gssdp-net-win32.c
new file mode 100644
index 0000000..df5b861
--- /dev/null
+++ b/libgssdp/gssdp-net-win32.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2016 Jens Georg <mail jensge org>
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#define _WIN32_WINNT 0x502
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <iphlpapi.h>
+typedef int socklen_t;
+/* from the return value of inet_addr */
+
+#include "gssdp-error.h"
+#include "gssdp-net.h"
+
+gboolean
+gssdp_net_init (GError **error)
+{
+        WSADATA wsaData = {0};
+        gchar *message = NULL;
+
+        if (WSAStartup (MAKEWORD (2,2), &wsaData) == 0) {
+            return TRUE;
+        }
+
+
+        message = g_win32_error_message (WSAGetLastError ());
+        g_set_error_literal (error,
+                             GSSDP_ERROR,
+                             GSSDP_ERROR_FAILED,
+                             message);
+        g_free (message);
+
+        return FALSE;
+}
+
+void
+gssdp_net_shutdown (void)
+{
+        WSACleanup ();
+}
+
+static gboolean
+is_primary_adapter (PIP_ADAPTER_ADDRESSES adapter)
+{
+        int family =
+                adapter->FirstUnicastAddress->Address.lpSockaddr->sa_family;
+
+        return !(adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK ||
+                 family == AF_INET6);
+}
+
+static gboolean
+extract_address_and_prefix (PIP_ADAPTER_UNICAST_ADDRESS  adapter,
+                            PIP_ADAPTER_PREFIX           prefix,
+                            char                        *iface,
+                            char                        *network) {
+        DWORD ret = 0;
+        DWORD len = INET6_ADDRSTRLEN;
+
+        ret = WSAAddressToStringA (adapter->Address.lpSockaddr,
+                                   adapter->Address.iSockaddrLength,
+                                   NULL,
+                                   iface,
+                                   &len);
+        if (ret != 0)
+                return FALSE;
+
+        if (prefix) {
+                ret = WSAAddressToStringA (prefix->Address.lpSockaddr,
+                                           prefix->Address.iSockaddrLength,
+                                           NULL,
+                                           network,
+                                           &len);
+                if (ret != 0)
+                        return FALSE;
+        } else if (strcmp (iface, "127.0.0.1"))
+                strcpy (network, "127.0.0.0");
+        else
+                return FALSE;
+
+        return TRUE;
+}
+
+int
+gssdp_net_query_ifindex (GSSDPNetworkDevice *device)
+{
+        /* TODO: if_nametoindex is supported on Vista or later */
+        return -1;
+}
+
+char *
+gssdp_net_arp_lookup (GSSDPNetworkDevice *device, const char *ip_address)
+{
+        /* TODO: Is there a way to make this work? */
+        /* GetIpNetTable / GetIpNetTable2 for Vista (ipv6) */
+        return g_strdup (ip_address);
+}
+
+gboolean
+gssdp_net_get_host_ip (GSSDPNetworkDevice *device)
+{
+        GList *up_ifaces = NULL, *ifaceptr = NULL;
+        ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
+                      GAA_FLAG_SKIP_DNS_SERVER |
+                      GAA_FLAG_SKIP_MULTICAST;
+        DWORD size = 15360; /* Use 15k buffer initially as documented in MSDN */
+        DWORD ret;
+        PIP_ADAPTER_ADDRESSES adapters_addresses;
+        PIP_ADAPTER_ADDRESSES adapter;
+
+        do {
+                adapters_addresses = (PIP_ADAPTER_ADDRESSES) g_malloc0 (size);
+                ret = GetAdaptersAddresses (AF_UNSPEC,
+                                            flags,
+                                            NULL,
+                                            adapters_addresses,
+                                            &size);
+                if (ret == ERROR_BUFFER_OVERFLOW)
+                        g_free (adapters_addresses);
+        } while (ret == ERROR_BUFFER_OVERFLOW);
+
+        if (ret == ERROR_SUCCESS)
+                for (adapter = adapters_addresses;
+                     adapter != NULL;
+                     adapter = adapter->Next) {
+                        if (adapter->FirstUnicastAddress == NULL)
+                                continue;
+                        if (adapter->OperStatus != IfOperStatusUp)
+                                continue;
+                        /* skip Point-to-Point devices */
+                        if (adapter->IfType == IF_TYPE_PPP)
+                                continue;
+
+                        if (device->iface_name != NULL &&
+                            strcmp (device->iface_name, adapter->AdapterName) != 0)
+                                continue;
+
+                        /* I think that IPv6 is done via pseudo-adapters, so
+                         * that there are either IPv4 or IPv6 addresses defined
+                         * on the adapter.
+                         * Loopback-Devices and IPv6 go to the end of the list,
+                         * IPv4 to the front
+                         */
+                        if (is_primary_adapter (adapter))
+                                up_ifaces = g_list_prepend (up_ifaces, adapter);
+                        else
+                                up_ifaces = g_list_append (up_ifaces, adapter);
+                }
+
+        for (ifaceptr = up_ifaces;
+             ifaceptr != NULL;
+             ifaceptr = ifaceptr->next) {
+                char ip[INET6_ADDRSTRLEN];
+                char prefix[INET6_ADDRSTRLEN];
+                const char *p, *q;
+                PIP_ADAPTER_UNICAST_ADDRESS address;
+                PIP_ADAPTER_PREFIX address_prefix;
+
+                p = NULL;
+
+                adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
+
+                for (address_prefix = adapter->FirstPrefix;
+                     address_prefix != NULL;
+                     address_prefix = address_prefix->Next)
+                        if (address_prefix->Address.lpSockaddr->sa_family == AF_INET)
+                                break;
+
+                if (address_prefix == NULL)
+                        continue;
+
+                for (address = adapter->FirstUnicastAddress;
+                     address != NULL;
+                     address = address->Next) {
+                        if (address->Address.lpSockaddr->sa_family != AF_INET)
+                                continue;
+
+                        if (extract_address_and_prefix (address,
+                                                        address_prefix,
+                                                        ip,
+                                                        prefix)) {
+                                p = ip;
+                                q = prefix;
+                        }
+
+                        if (p != NULL) {
+                                gint32 mask = 0;
+
+                                device->host_ip = g_strdup (p);
+                                /* This relies on the compiler doing an arithmetic
+                                 * shift here!
+                                 */
+                                if (address_prefix->PrefixLength > 0) {
+                                        mask = (gint32) 0x80000000;
+                                        mask >>= address_prefix->PrefixLength - 1;
+                                }
+                                device->mask.sin_family = AF_INET;
+                                device->mask.sin_port = 0;
+                                device->mask.sin_addr.s_addr = htonl ((guint32) mask);
+
+                                if (device->iface_name == NULL)
+                                        device->iface_name = g_strdup (adapter->AdapterName);
+                                if (device->network == NULL)
+                                        device->network = g_strdup (q);
+
+                                device->index = gssdp_net_query_ifindex (device);
+                                break;
+                        }
+                }
+
+                if (p != NULL)
+                        break;
+
+        }
+        g_list_free (up_ifaces);
+        g_free (adapters_addresses);
+
+        return TRUE;
+}
diff --git a/libgssdp/gssdp-net.h b/libgssdp/gssdp-net.h
new file mode 100644
index 0000000..02f2901
--- /dev/null
+++ b/libgssdp/gssdp-net.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 Jens Georg <mail jensge org>
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GSSDP_NET_H
+#define GSSDP_NET_H
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#ifdef G_OS_WIN32
+#include <winsock2.h>
+typedef unsigned long in_addr_t;
+#else
+#include <netinet/in.h>
+#endif
+
+struct _GSSDPNetworkDevice {
+        char *iface_name;
+        char *host_ip;
+        GInetAddress *host_addr;
+        char *network;
+        struct sockaddr_in mask;
+        gint index;
+};
+typedef struct _GSSDPNetworkDevice GSSDPNetworkDevice;
+
+G_GNUC_INTERNAL gboolean
+gssdp_net_init                  (GError **error);
+
+G_GNUC_INTERNAL void
+gssdp_net_shutdown              (void);
+
+G_GNUC_INTERNAL gboolean
+gssdp_net_get_host_ip           (GSSDPNetworkDevice *device);
+
+G_GNUC_INTERNAL int
+gssdp_net_query_ifindex         (GSSDPNetworkDevice *device);
+
+G_GNUC_INTERNAL char*
+gssdp_net_arp_lookup            (GSSDPNetworkDevice *device,
+                                 const char *ip_address);
+
+#endif /* GSSDP_NET_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]