summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Georg <jensg@openismus.com>2013-10-19 06:57:11 +0200
committerJens Georg <mail@jensge.org>2013-10-19 07:50:19 +0200
commitc34053b4185b2c2200f6bd8af24d10143525a942 (patch)
tree49a0c95bf7af738ecb28a2780665ff0831c02c97
parentdd25eb8349c5e6dc17f95f5625adc848fa3efc41 (diff)
downloadgssdp-wip/refactor-get-host-ip.tar.gz
Split get_host_ip functionwip/refactor-get-host-ip
-rw-r--r--configure.ac8
-rw-r--r--libgssdp/Makefile.am8
-rw-r--r--libgssdp/gssdp-client.c463
-rw-r--r--libgssdp/gssdp-net-bionic.c225
-rw-r--r--libgssdp/gssdp-net-unix.c104
-rw-r--r--libgssdp/gssdp-net-win32.c179
-rw-r--r--libgssdp/gssdp-net.h28
-rw-r--r--libgssdp/gssdp-resource-browser.c2
8 files changed, 559 insertions, 458 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..5c80808 100644
--- a/libgssdp/gssdp-client.c
+++ b/libgssdp/gssdp-client.c
@@ -34,34 +34,18 @@
#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 +54,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 +72,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 +161,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 +364,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 +1053,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 +1062,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..30dafbb
--- /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 */
+
+#include "gssdp-error.h"
+#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..e42d5ee
--- /dev/null
+++ b/libgssdp/gssdp-net.h
@@ -0,0 +1,28 @@
+#ifndef __GSSDP_HOST_IP_H__
+#define __GSSDP_HOST_IP_H__
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+
+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__ */
diff --git a/libgssdp/gssdp-resource-browser.c b/libgssdp/gssdp-resource-browser.c
index 00e9a17..a5fa586 100644
--- a/libgssdp/gssdp-resource-browser.c
+++ b/libgssdp/gssdp-resource-browser.c
@@ -932,7 +932,7 @@ check_target_compat (GSSDPResourceBrowser *resource_browser,
return FALSE;
}
- return (uint) version >= resource_browser->priv->version;
+ return (guint) version >= resource_browser->priv->version;
}
static void