diff options
author | Jens Georg <jensg@openismus.com> | 2013-10-19 06:57:11 +0200 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2013-10-19 07:50:19 +0200 |
commit | c34053b4185b2c2200f6bd8af24d10143525a942 (patch) | |
tree | 49a0c95bf7af738ecb28a2780665ff0831c02c97 | |
parent | dd25eb8349c5e6dc17f95f5625adc848fa3efc41 (diff) | |
download | gssdp-wip/refactor-get-host-ip.tar.gz |
Split get_host_ip functionwip/refactor-get-host-ip
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | libgssdp/Makefile.am | 8 | ||||
-rw-r--r-- | libgssdp/gssdp-client.c | 463 | ||||
-rw-r--r-- | libgssdp/gssdp-net-bionic.c | 225 | ||||
-rw-r--r-- | libgssdp/gssdp-net-unix.c | 104 | ||||
-rw-r--r-- | libgssdp/gssdp-net-win32.c | 179 | ||||
-rw-r--r-- | libgssdp/gssdp-net.h | 28 | ||||
-rw-r--r-- | libgssdp/gssdp-resource-browser.c | 2 |
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 |