diff options
author | Christophe Guiraud <christophe.guiraud@intel.com> | 2013-09-09 10:00:46 +0200 |
---|---|---|
committer | rmerlino <regis.merlino@intel.com> | 2013-12-12 14:54:21 +0100 |
commit | 93345aa14496ff074d05d19d747017ac01cd5433 (patch) | |
tree | 907a3ad4193fd350f0fa4d78a4d69a9ab205dcb7 | |
parent | 344aafd8c04ddf9d0e8af7b0bca1307fec53b6a7 (diff) | |
download | dleyna-server-93345aa14496ff074d05d19d747017ac01cd5433.tar.gz |
[Device] Fix wake-on ip address used for broadcast
When the wake-on method is UDP broadcast, we now use the broadcast
IP address of the active context newtork interface.
if the broadcast IP address can't be retrieved, we use the IP address
provided in the network interface info.
Signed-off-by: Christophe Guiraud <christophe.guiraud@intel.com>
-rw-r--r-- | libdleyna/server/device.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c index 2bb9901..b09814a 100644 --- a/libdleyna/server/device.c +++ b/libdleyna/server/device.c @@ -22,6 +22,15 @@ #include <string.h> #include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <ifaddrs.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <net/if.h> + #include <libgupnp/gupnp-error.h> #include <libgupnp-dlna/gupnp-dlna-profile.h> #include <libgupnp-dlna/gupnp-dlna-profile-guesser.h> @@ -5996,6 +6005,70 @@ on_complete: return error; } +static gboolean prv_get_interface_ip_address(struct sockaddr *sock_address, + gchar *host) +{ + socklen_t sock_len; + gint family; + gboolean res = FALSE; + + family = sock_address->sa_family; + + if (family != AF_INET && family != AF_INET6) + goto on_exit; + + if (family == AF_INET) + sock_len = sizeof(struct sockaddr_in); + else + sock_len = sizeof(struct sockaddr_in6); + + if (getnameinfo(sock_address, sock_len, host, + NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) { + if (family == AF_INET6) + inet_ntop(AF_INET6, &sock_address, host, NI_MAXHOST); + + res = TRUE; + } + +on_exit: + return res; +} + +static gchar *prv_get_broadcast_ip_address(gchar *ip_address) +{ + struct ifaddrs *ifaddr; + struct ifaddrs *ifa; + char host[NI_MAXHOST]; + gchar *broadcast_ip_address = NULL; + + if (getifaddrs(&ifaddr) == -1) { + DLEYNA_LOG_WARNING("Failed to call getifaddrs"); + goto on_exit; + } + + ifa = ifaddr; + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if ((ifa->ifa_addr == NULL) || + (!prv_get_interface_ip_address(ifa->ifa_addr, host)) || + strcmp(host, ip_address)) + continue; + + if ((ifa->ifa_flags & IFF_BROADCAST) && + (ifa->ifa_ifu.ifu_broadaddr != NULL) && + prv_get_interface_ip_address(ifa->ifa_ifu.ifu_broadaddr, + host)) { + broadcast_ip_address = g_strdup(host); + + break; + } + } + + freeifaddrs(ifaddr); + +on_exit: + + return broadcast_ip_address; +} void dls_device_wake(dls_client_t *client, dls_task_t *task) { @@ -6010,6 +6083,7 @@ void dls_device_wake(dls_client_t *client, dls_task_t *task) gsize packet_len; guint8 *packet = NULL; gchar *wake_on_ip_address; + gchar *broadcast_ip_address = NULL; DLEYNA_LOG_DEBUG("Enter"); @@ -6058,6 +6132,18 @@ void dls_device_wake(dls_client_t *client, dls_task_t *task) DLEYNA_LOG_DEBUG("Context IP Address = %s", context->ip_address); DLEYNA_LOG_DEBUG("Wake ON IP Address = %s", wake_on_ip_address); + if (broadcast) { + broadcast_ip_address = prv_get_broadcast_ip_address( + context->ip_address); + + if (broadcast_ip_address != NULL) { + wake_on_ip_address = broadcast_ip_address; + + DLEYNA_LOG_DEBUG("Use Broadcast IP Address = %s", + broadcast_ip_address); + } + } + host_inet_address = g_inet_address_new_from_string(wake_on_ip_address); if (host_inet_address == NULL) { @@ -6112,6 +6198,8 @@ on_complete: (void) g_idle_add(dls_async_task_complete, cb_data); on_exit: + g_free(broadcast_ip_address); + DLEYNA_LOG_DEBUG("Exit"); return; |