[gssdp/wip/refactor-get-host-ip] Split get_host_ip function



commit 4e4a24c7018a3bf1aa131aa4a367a9b5290d034a
Author: Jens Georg <jensg openismus com>
Date:   Sat Oct 19 06:57:11 2013 +0200

    Split get_host_ip function

 configure.ac                |    8 +
 libgssdp/Makefile.am        |    8 +-
 libgssdp/gssdp-client.c     |  468 +------------------------------------------
 libgssdp/gssdp-net-bionic.c |  225 +++++++++++++++++++++
 libgssdp/gssdp-net-unix.c   |  104 ++++++++++
 libgssdp/gssdp-net-win32.c  |  179 +++++++++++++++++
 libgssdp/gssdp-net.h        |   22 ++
 7 files changed, 552 insertions(+), 462 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5053174..3451343 100644
--- a/configure.ac
+++ b/configure.ac
@@ -131,6 +131,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"])
+
 GTK_DOC_CHECK([1.14], [--flavour no-tmpl])
 
 AC_CONFIG_FILES([
diff --git a/libgssdp/Makefile.am b/libgssdp/Makefile.am
index c250f64..2069114 100644
--- a/libgssdp/Makefile.am
+++ b/libgssdp/Makefile.am
@@ -42,6 +42,7 @@ libgssdp_1_0_la_LDFLAGS = -version-info $(LTVERSION)
 libgssdp_1_0_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      \
@@ -51,15 +52,20 @@ libgssdp_1_0_la_SOURCES = $(introspection_sources)  \
 libgssdp_1_0_la_LIBADD = $(LIBGSSDP_LIBS)
 
 if OS_WIN32
-
+libgssdp_1_0_la_SOURCES += gssdp-net-win32.c
 libgssdp_1_0_la_LIBADD += -lws2_32 -liphlpapi
 libgssdp_1_0_la_LDFLAGS += -no-undefined
 endif
 
 if TARGET_ANDROID
+libgssdp_1_0_la_SOURCES += gssdp-net-bionic.c
 libgssdp_1_0_la_LIBADD += -llog
 endif
 
+if TARGET_GENERIC
+libgssdp_1_0_la_SOURCES += gssdp-net-unix.c
+endif
+
 EXTRA_DIST = gssdp-marshal.list
 
 CLEANFILES = $(BUILT_SOURCES)
diff --git a/libgssdp/gssdp-client.c b/libgssdp/gssdp-client.c
index baec893..39d90ea 100644
--- a/libgssdp/gssdp-client.c
+++ b/libgssdp/gssdp-client.c
@@ -33,35 +33,14 @@
 #include <config.h>
 #include <sys/types.h>
 #include <glib.h>
-#ifndef G_OS_WIN32
-#include <sys/socket.h>
 #include <sys/utsname.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#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>
 
 #include "gssdp-client.h"
@@ -70,14 +49,8 @@ typedef unsigned long in_addr_t;
 #include "gssdp-socket-source.h"
 #include "gssdp-marshal.h"
 #include "gssdp-protocol.h"
+#include "gssdp-net.h"
 
-#ifndef INET6_ADDRSTRLEN
-#define INET6_ADDRSTRLEN 46
-#endif
-
-#ifdef __BIONIC__
-#include <android/log.h>
-#endif
 
 /* Size of the buffer used for reading from the socket */
 #define BUF_SIZE 65536
@@ -94,14 +67,6 @@ G_DEFINE_TYPE_EXTENDED (GSSDPClient,
                                 (G_TYPE_INITABLE,
                                  gssdp_client_initable_iface_init));
 
-struct _GSSDPNetworkDevice {
-        char *iface_name;
-        char *host_ip;
-        char *network;
-        struct sockaddr_in mask;
-};
-typedef struct _GSSDPNetworkDevice GSSDPNetworkDevice;
-
 struct _GSSDPClientPrivate {
         char              *server_id;
 
@@ -191,21 +156,8 @@ gssdp_client_initable_init (GInitable                   *initable,
         if (client->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))
@@ -407,9 +359,8 @@ gssdp_client_finalize (GObject *object)
         GSSDPClient *client;
 
         client = GSSDP_CLIENT (object);
-#ifdef G_OS_WIN32
-        WSACleanup ();
-#endif
+
+        gssdp_net_shutdown ();
 
         g_free (client->priv->server_id);
         g_free (client->priv->device.iface_name);
@@ -1097,50 +1048,6 @@ search_socket_source_cb (G_GNUC_UNUSED GIOChannel  *source,
         return socket_source_cb (client->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
-
 /*
  * 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
@@ -1150,368 +1057,7 @@ extract_address_and_prefix (PIP_ADAPTER_UNICAST_ADDRESS  adapter,
 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;
-
-                p = NULL;
-
-                adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
-                address = adapter->FirstUnicastAddress;
-
-                if (address->Address.lpSockaddr->sa_family != AF_INET)
-                        continue;
-
-                if (extract_address_and_prefix (address,
-                                                adapter->FirstPrefix,
-                                                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 (adapter->FirstPrefix->PrefixLength > 0) {
-                                mask = (gint32) 0x80000000;
-                                mask >>= adapter->FirstPrefix->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;
-                }
-
-        }
-        g_list_free (up_ifaces);
-        g_free (adapters_addresses);
-
-        return TRUE;
-#elif __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_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;
-#else
-        struct ifaddrs *ifa_list, *ifa;
-        GList *up_ifaces, *ifaceptr;
-
-        up_ifaces = NULL;
-
-        if (getifaddrs (&ifa_list) != 0) {
-                g_error ("Failed to retrieve list of network interfaces:\n%s\n",
-                         strerror (errno));
-
-                return FALSE;
-        }
-
-        for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
-                if (ifa->ifa_addr == NULL)
-                        continue;
-
-                if (device->iface_name &&
-                    strcmp (device->iface_name, ifa->ifa_name) != 0)
-                        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;
-
-                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);
-                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);
-                break;
-        }
-
-        g_list_free (up_ifaces);
-        freeifaddrs (ifa_list);
-
-        return TRUE;
-#endif
+        return gssdp_net_get_host_ip (device);
 }
 
 static gboolean
diff --git a/libgssdp/gssdp-net-bionic.c b/libgssdp/gssdp-net-bionic.c
new file mode 100644
index 0000000..8dd1b48
--- /dev/null
+++ b/libgssdp/gssdp-net-bionic.c
@@ -0,0 +1,225 @@
+
+#include <config.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <stdlib.h>
+
+#include "gssdp-net.h"
+
+gboolean
+gssdp_net_init (GError **error)
+{
+        return TRUE;
+}
+
+void
+gssdp_net_shutdown (void)
+{
+        /* Do nothing. */
+}
+
+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-unix.c b/libgssdp/gssdp-net-unix.c
new file mode 100644
index 0000000..e6d7c23
--- /dev/null
+++ b/libgssdp/gssdp-net-unix.c
@@ -0,0 +1,104 @@
+#include <config.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+
+#include "gssdp-net.h"
+
+gboolean
+gssdp_net_init (GError **error)
+{
+        return TRUE;
+}
+
+void
+gssdp_net_shutdown (void)
+{
+        /* Do nothing. */
+}
+
+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_error ("Failed to retrieve list of network interfaces:\n%s\n",
+                         strerror (errno));
+
+                return FALSE;
+        }
+
+        for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
+                if (ifa->ifa_addr == NULL)
+                        continue;
+
+                if (device->iface_name &&
+                    strcmp (device->iface_name, ifa->ifa_name) != 0)
+                        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;
+
+                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);
+                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);
+                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..ec0ff02
--- /dev/null
+++ b/libgssdp/gssdp-net-win32.c
@@ -0,0 +1,179 @@
+#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;
+
+#include "gssdp-net.h"
+
+gboolean
+gssdp_net_init (GError **error)
+{
+        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);
+
+                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;
+}
+
+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_ADDRESSES adapter;
+                PIP_ADAPTER_UNICAST_ADDRESS address;
+
+                p = NULL;
+
+                adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
+                address = adapter->FirstUnicastAddress;
+
+                if (address->Address.lpSockaddr->sa_family != AF_INET)
+                        continue;
+
+                if (extract_address_and_prefix (address,
+                                                adapter->FirstPrefix,
+                                                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 (adapter->FirstPrefix->PrefixLength > 0) {
+                                mask = (gint32) 0x80000000;
+                                mask >>= adapter->FirstPrefix->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;
+                }
+
+        }
+        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..06b0301
--- /dev/null
+++ b/libgssdp/gssdp-net.h
@@ -0,0 +1,22 @@
+#ifndef __GSSDP_HOST_IP_H__
+#define __GSSDP_HOST_IP_H__
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#include <netinet/in.h>
+
+struct _GSSDPNetworkDevice {
+        char *iface_name;
+        char *host_ip;
+        char *network;
+        struct sockaddr_in mask;
+};
+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);
+
+#endif /* __GSSDP_HOST_IP_H__ */



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