diff --git a/Makefile b/Makefile index 20dc096..39cad38 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ else LDFLAGS += -lsocket endif ifeq ($(OS),Darwin) - CFLAGS += -arch i386 -arch x86_64 + CFLAGS += -arch x86_64 LIBEXT := .dylib SHARED := -dynamiclib -install_name libhdhomerun$(LIBEXT) endif diff --git a/hdhomerun_config.c b/hdhomerun_config.c index 8c5bace..6af8e6e 100644 --- a/hdhomerun_config.c +++ b/hdhomerun_config.c @@ -91,27 +91,37 @@ static int discover_print(char *target_ip_str) } struct hdhomerun_discover_device_t result_list[64]; - int count = hdhomerun_discover_find_devices_custom_v2(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, 64); - if (count < 0) { + int result_count = hdhomerun_discover_find_devices_custom_v2(target_ip, HDHOMERUN_DEVICE_TYPE_WILDCARD, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, 64); + if (result_count < 0) { fprintf(stderr, "error sending discover request\n"); return -1; } - if (count == 0) { - printf("no devices found\n"); - return 0; - } - int index; - for (index = 0; index < count; index++) { - struct hdhomerun_discover_device_t *result = &result_list[index]; + struct hdhomerun_discover_device_t *result = result_list; + struct hdhomerun_discover_device_t *result_end = result_list + result_count; + + int valid_count = 0; + while (result < result_end) { + if (result->device_id == 0) { + result++; + continue; + } + printf("hdhomerun device %08X found at %u.%u.%u.%u\n", (unsigned int)result->device_id, (unsigned int)(result->ip_addr >> 24) & 0x0FF, (unsigned int)(result->ip_addr >> 16) & 0x0FF, (unsigned int)(result->ip_addr >> 8) & 0x0FF, (unsigned int)(result->ip_addr >> 0) & 0x0FF ); + + valid_count++; + result++; } - return count; + if (valid_count == 0) { + printf("no devices found\n"); + } + + return valid_count; } static int cmd_get(const char *item) diff --git a/hdhomerun_discover.c b/hdhomerun_discover.c index 11c6ed5..c8b271d 100644 --- a/hdhomerun_discover.c +++ b/hdhomerun_discover.c @@ -168,34 +168,12 @@ static bool hdhomerun_discover_send_internal(struct hdhomerun_discover_t *ds, st return hdhomerun_sock_sendto(dss->sock, target_ip, HDHOMERUN_DISCOVER_UDP_PORT, tx_pkt->start, tx_pkt->end - tx_pkt->start, 0); } -static bool hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id) +static bool hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) { - bool result = false; - - /* - * Send subnet broadcast using each local ip socket. - * This will work with multiple separate 169.254.x.x interfaces. - */ - unsigned int i; - for (i = 1; i < ds->sock_count; i++) { - struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; - uint32_t target_ip = dss->local_ip | ~dss->subnet_mask; - result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id); + if (target_ip == 0x00000000) { + target_ip = 0xFFFFFFFF; } - /* - * If no local ip sockets then fall back to sending a global broadcast letting the OS choose the interface. - */ - if (!result) { - struct hdhomerun_discover_sock_t *dss = &ds->socks[0]; - result = hdhomerun_discover_send_internal(ds, dss, 0xFFFFFFFF, device_type, device_id); - } - - return result; -} - -static bool hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) -{ bool result = false; /* @@ -205,11 +183,14 @@ static bool hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, u unsigned int i; for (i = 1; i < ds->sock_count; i++) { struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; - if (dss->subnet_mask == 0) { - continue; - } - if ((target_ip & dss->subnet_mask) != (dss->local_ip & dss->subnet_mask)) { - continue; + + if (target_ip != 0xFFFFFFFF) { + if (dss->subnet_mask == 0) { + continue; + } + if ((target_ip & dss->subnet_mask) != (dss->local_ip & dss->subnet_mask)) { + continue; + } } result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id); @@ -226,15 +207,6 @@ static bool hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, u return result; } -static bool hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) -{ - if (target_ip == 0) { - return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id); - } else { - return hdhomerun_discover_send_target_ip(ds, target_ip, device_type, device_id); - } -} - static bool hdhomerun_discover_is_legacy(uint32_t device_id) { switch (device_id >> 20) { diff --git a/hdhomerun_os_posix.h b/hdhomerun_os_posix.h index baab8e5..d3dc5cb 100644 --- a/hdhomerun_os_posix.h +++ b/hdhomerun_os_posix.h @@ -53,7 +53,7 @@ typedef struct { #define LIBHDHOMERUN_API -#if !defined(alignas) +#if !defined(alignas) && !defined(__cplusplus) #define alignas(n) __attribute__((aligned(n))) #endif diff --git a/hdhomerun_sock_posix.c b/hdhomerun_sock_posix.c index d71acf0..ad72709 100644 --- a/hdhomerun_sock_posix.c +++ b/hdhomerun_sock_posix.c @@ -1,7 +1,7 @@ /* * hdhomerun_sock_posix.c * - * Copyright © 2010-2016 Silicondust USA Inc. . + * Copyright © 2010-2019 Silicondust USA Inc. . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,14 +23,6 @@ #include #include -#ifndef SIOCGIFCONF -#include -#endif - -#ifndef _SIZEOF_ADDR_IFREQ -#define _SIZEOF_ADDR_IFREQ(x) sizeof(x) -#endif - #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif @@ -39,28 +31,79 @@ struct hdhomerun_sock_t { int sock; }; +static bool hdhomerun_local_ip_info_add(struct hdhomerun_local_ip_info_t *ip_info, int sock, struct ifreq *ifr) +{ + /* Flags. */ + if (ioctl(sock, SIOCGIFFLAGS, ifr) != 0) { + return false; + } + + if ((ifr->ifr_flags & IFF_UP) == 0) { + return false; + } + if ((ifr->ifr_flags & IFF_RUNNING) == 0) { + return false; + } + + /* Local IP address. */ + if (ioctl(sock, SIOCGIFADDR, ifr) != 0) { + return false; + } + + struct sockaddr_in *ip_addr_in = (struct sockaddr_in *)&ifr->ifr_addr; + uint32_t ip_addr = ntohl(ip_addr_in->sin_addr.s_addr); + if (ip_addr == 0) { + return false; + } + + /* Subnet mask. */ + if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) { + return false; + } + + struct sockaddr_in *subnet_mask_in = (struct sockaddr_in *)&ifr->ifr_addr; + uint32_t subnet_mask = ntohl(subnet_mask_in->sin_addr.s_addr); + + /* Result. */ + if (ip_info) { + ip_info->ip_addr = ip_addr; + ip_info->subnet_mask = subnet_mask; + } + + return true; +} + +#if defined(LIBHDHOMERUN_USE_LEGACY_SIOCGIFCONF) int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count) { - int sock = socket(AF_INET, SOCK_DGRAM, 0); + int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (sock == -1) { return -1; } struct ifconf ifc; - size_t ifreq_buffer_size = 1024; + size_t ifreq_buffer_size = 0; + void *ifreq_buffer = NULL; while (1) { - ifc.ifc_len = (int)ifreq_buffer_size; - ifc.ifc_buf = (char *)malloc(ifreq_buffer_size); - if (!ifc.ifc_buf) { + ifreq_buffer_size += 64 * sizeof(struct ifreq); + + void *old_buffer = ifreq_buffer; + ifreq_buffer = realloc(old_buffer, ifreq_buffer_size); + if (!ifreq_buffer) { + if (old_buffer) { + free(old_buffer); + } close(sock); return -1; } - memset(ifc.ifc_buf, 0, ifreq_buffer_size); + ifc.ifc_len = (int)ifreq_buffer_size; + ifc.ifc_buf = (char *)ifreq_buffer; + memset(ifreq_buffer, 0, ifreq_buffer_size); if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) { - free(ifc.ifc_buf); + free(ifreq_buffer); close(sock); return -1; } @@ -68,64 +111,85 @@ int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int if (ifc.ifc_len < (int)ifreq_buffer_size) { break; } - - free(ifc.ifc_buf); - ifreq_buffer_size += 1024; } + struct hdhomerun_local_ip_info_t *ip_info = (max_count > 0) ? ip_info_list : NULL; char *ptr = ifc.ifc_buf; char *end = ifc.ifc_buf + ifc.ifc_len; - int count = 0; - while (ptr < end) { + + while (ptr + sizeof(struct ifreq) <= end) { struct ifreq *ifr = (struct ifreq *)ptr; - ptr += _SIZEOF_ADDR_IFREQ(*ifr); + ptr += sizeof(struct ifreq); - /* Flags. */ - if (ioctl(sock, SIOCGIFFLAGS, ifr) != 0) { + if (!hdhomerun_local_ip_info_add(ip_info, sock, ifr)) { continue; } - if ((ifr->ifr_flags & IFF_UP) == 0) { - continue; - } - if ((ifr->ifr_flags & IFF_RUNNING) == 0) { - continue; - } - - /* Local IP address. */ - if (ioctl(sock, SIOCGIFADDR, ifr) != 0) { - continue; - } - - struct sockaddr_in *ip_addr_in = (struct sockaddr_in *)&(ifr->ifr_addr); - uint32_t ip_addr = ntohl(ip_addr_in->sin_addr.s_addr); - if (ip_addr == 0) { - continue; - } - - /* Subnet mask. */ - if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) { - continue; - } - - struct sockaddr_in *subnet_mask_in = (struct sockaddr_in *)&(ifr->ifr_addr); - uint32_t subnet_mask = ntohl(subnet_mask_in->sin_addr.s_addr); - - /* Report. */ - if (count < max_count) { - struct hdhomerun_local_ip_info_t *ip_info = &ip_info_list[count]; - ip_info->ip_addr = ip_addr; - ip_info->subnet_mask = subnet_mask; - } - count++; + + if (count >= max_count) { + ip_info = NULL; + } else { + ip_info++; + } } - free(ifc.ifc_buf); + free(ifreq_buffer); close(sock); return count; } +#else +int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count) +{ + int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock == -1) { + return -1; + } + + struct if_nameindex *ni = if_nameindex(); + if (!ni) { + close(sock); + return -1; + } + + struct hdhomerun_local_ip_info_t *ip_info = (max_count > 0) ? ip_info_list : NULL; + struct if_nameindex *iter = ni; + int count = 0; + + while (1) { + if (!iter->if_name) { + if (iter->if_index == 0) { + break; + } + + iter++; + continue; + } + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, iter->if_name, IF_NAMESIZE); + iter++; + + if (!hdhomerun_local_ip_info_add(ip_info, sock, &ifr)) { + continue; + } + + count++; + + if (count >= max_count) { + ip_info = NULL; + } else { + ip_info++; + } + } + + if_freenameindex(ni); + close(sock); + return count; +} +#endif static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol) {