From 99dc6b5ed0b8a0d8388ef16d4265a186172133fc Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 16 Apr 2013 11:48:02 -0400 Subject: [PATCH] Port get_host_ip() to Android/Bionic Add Bionic netlink code for network configuration discovery. https://bugzilla.gnome.org/show_bug.cgi?id=707161 --- configure.ac | 17 ++++ libgssdp/Makefile.am | 4 + libgssdp/gssdp-client.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) diff --git a/configure.ac b/configure.ac index dd8fc2b..e5bec47 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,9 @@ GNOME_COMPILE_WARNINGS AM_SILENT_RULES([yes]) +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + AC_SEARCH_LIBS([strerror],[cposix]) AC_PROG_CC AC_HEADER_STDC @@ -114,6 +117,20 @@ esac AC_MSG_RESULT([$os_win32]) AM_CONDITIONAL(OS_WIN32, [test $os_win32 = yes]) +dnl Check for Android +AC_MSG_CHECKING([for Android as target OS]) +target_android=no +case "$target_os" in + linux-android*) + target_android=yes + ;; + *) + target_android=no + ;; +esac +AC_MSG_RESULT([$target_android]) +AM_CONDITIONAL(TARGET_ANDROID, [test $target_android = yes]) + GTK_DOC_CHECK([1.0]) AC_CONFIG_FILES([ diff --git a/libgssdp/Makefile.am b/libgssdp/Makefile.am index f8d4dc2..c250f64 100644 --- a/libgssdp/Makefile.am +++ b/libgssdp/Makefile.am @@ -56,6 +56,10 @@ libgssdp_1_0_la_LIBADD += -lws2_32 -liphlpapi libgssdp_1_0_la_LDFLAGS += -no-undefined endif +if TARGET_ANDROID +libgssdp_1_0_la_LIBADD += -llog +endif + EXTRA_DIST = gssdp-marshal.list CLEANFILES = $(BUILT_SOURCES) diff --git a/libgssdp/gssdp-client.c b/libgssdp/gssdp-client.c index 876246c..baec893 100644 --- a/libgssdp/gssdp-client.c +++ b/libgssdp/gssdp-client.c @@ -54,7 +54,13 @@ typedef unsigned long in_addr_t; #ifndef G_OS_WIN32 #include #include +#ifndef __BIONIC__ #include +#else +#include +#include +#include +#endif #endif #include @@ -69,6 +75,10 @@ typedef unsigned long in_addr_t; #define INET6_ADDRSTRLEN 46 #endif +#ifdef __BIONIC__ +#include +#endif + /* Size of the buffer used for reading from the socket */ #define BUF_SIZE 65536 @@ -1240,6 +1250,196 @@ get_host_ip (GSSDPNetworkDevice *device) 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; -- 2.7.4