mirror of
https://github.com/Silicondust/libhdhomerun
synced 2025-07-05 12:36:48 -07:00
20221020
This commit is contained in:
parent
0ea5574fa5
commit
a8ac7a6659
10 changed files with 437 additions and 150 deletions
|
@ -98,7 +98,7 @@ void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs)
|
|||
|
||||
static bool hdhomerun_control_connect_sock_discover(struct hdhomerun_control_sock_t *cs)
|
||||
{
|
||||
struct hdhomerun_discover_t *ds = hdhomerun_discover_create(NULL);
|
||||
struct hdhomerun_discover_t *ds = hdhomerun_discover_create(cs->dbg);
|
||||
if (!ds) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
struct hdhomerun_device_selector_t {
|
||||
struct hdhomerun_device_t **hd_list;
|
||||
size_t hd_count;
|
||||
struct hdhomerun_discover_t *ds;
|
||||
struct hdhomerun_debug_t *dbg;
|
||||
};
|
||||
|
||||
|
@ -53,6 +54,10 @@ void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds,
|
|||
free(hds->hd_list);
|
||||
}
|
||||
|
||||
if (hds->ds) {
|
||||
hdhomerun_discover_destroy(hds->ds);
|
||||
}
|
||||
|
||||
free(hds);
|
||||
}
|
||||
|
||||
|
@ -123,18 +128,55 @@ struct hdhomerun_device_t *hdhomerun_device_selector_find_device(struct hdhomeru
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int hdhomerun_device_selector_load_from_str_discover(struct hdhomerun_device_selector_t *hds, uint32_t target_ip, uint32_t device_id)
|
||||
static int hdhomerun_device_selector_load_from_str_discover(struct hdhomerun_device_selector_t *hds, uint32_t device_id, const struct sockaddr *device_addr)
|
||||
{
|
||||
struct hdhomerun_discover_device_t result;
|
||||
int discover_count = hdhomerun_discover_find_devices_custom_v2(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, device_id, &result, 1);
|
||||
if (discover_count != 1) {
|
||||
if (!hds->ds) {
|
||||
hds->ds = hdhomerun_discover_create(hds->dbg);
|
||||
if (!hds->ds) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t device_types[1];
|
||||
device_types[0] = HDHOMERUN_DEVICE_TYPE_TUNER;
|
||||
|
||||
if (device_id == 0) {
|
||||
device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
|
||||
}
|
||||
|
||||
int ret;
|
||||
if (hdhomerun_sock_sockaddr_is_addr(device_addr)) {
|
||||
if (device_id == HDHOMERUN_DEVICE_ID_WILDCARD) {
|
||||
ret = hdhomerun_discover2_find_devices_targeted(hds->ds, device_addr, device_types, 1);
|
||||
} else {
|
||||
ret = hdhomerun_discover2_find_device_id_targeted(hds->ds, device_addr, device_id);
|
||||
}
|
||||
} else {
|
||||
uint32_t flags = HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL;
|
||||
if (device_id == HDHOMERUN_DEVICE_ID_WILDCARD) {
|
||||
ret = hdhomerun_discover2_find_devices_broadcast(hds->ds, flags, device_types, 1);
|
||||
} else {
|
||||
ret = hdhomerun_discover2_find_device_id_broadcast(hds->ds, flags, device_id);
|
||||
}
|
||||
}
|
||||
if (ret <= 0) {
|
||||
hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_str_discover: device not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hdhomerun_discover2_device_t *device = hdhomerun_discover2_iter_device_first(hds->ds);
|
||||
struct hdhomerun_discover2_device_if_t *device_if = hdhomerun_discover2_iter_device_if_first(device);
|
||||
|
||||
device_id = hdhomerun_discover2_device_get_device_id(device);
|
||||
uint8_t tuner_count = hdhomerun_discover2_device_get_tuner_count(device);
|
||||
|
||||
struct sockaddr_storage actual_ip_addr;
|
||||
hdhomerun_discover2_device_if_get_ip_addr(device_if, &actual_ip_addr);
|
||||
|
||||
int count = 0;
|
||||
unsigned int tuner_index;
|
||||
for (tuner_index = 0; tuner_index < result.tuner_count; tuner_index++) {
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create(result.device_id, result.ip_addr, tuner_index, hds->dbg);
|
||||
for (tuner_index = 0; tuner_index < tuner_count; tuner_index++) {
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create_ex(device_id, (struct sockaddr *)&actual_ip_addr, tuner_index, hds->dbg);
|
||||
if (!hd) {
|
||||
continue;
|
||||
}
|
||||
|
@ -146,98 +188,206 @@ static int hdhomerun_device_selector_load_from_str_discover(struct hdhomerun_dev
|
|||
return count;
|
||||
}
|
||||
|
||||
static bool hdhomerun_device_selector_load_from_str_parse_device_id(const char *name, uint32_t *pdevice_id)
|
||||
{
|
||||
char *end;
|
||||
uint32_t device_id = (uint32_t)strtoul(name, &end, 16);
|
||||
if (end != name + 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*end != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*pdevice_id = device_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hdhomerun_device_selector_load_from_str_parse_dns(const char *name, struct sockaddr_storage *device_addr)
|
||||
{
|
||||
const char *ptr = name;
|
||||
if (*ptr == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
char c = *ptr++;
|
||||
if (c == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((c >= '0') && (c <= '9')) {
|
||||
continue;
|
||||
}
|
||||
if ((c >= 'a') && (c <= 'z')) {
|
||||
continue;
|
||||
}
|
||||
if ((c >= 'A') && (c <= 'Z')) {
|
||||
continue;
|
||||
}
|
||||
if ((c == '.') || (c == '-')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return hdhomerun_sock_getaddrinfo_addr_ex(AF_INET, name, device_addr);
|
||||
}
|
||||
|
||||
static int hdhomerun_device_selector_load_from_str_tail(struct hdhomerun_device_selector_t *hds, const char *tail, uint32_t device_id, struct sockaddr_storage *device_addr)
|
||||
{
|
||||
const char *ptr = tail;
|
||||
if (*ptr == 0) {
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, device_id, (struct sockaddr *)device_addr);
|
||||
}
|
||||
|
||||
if (*ptr == ':') {
|
||||
ptr++;
|
||||
|
||||
char *end;
|
||||
unsigned long port = strtoul(ptr + 1, &end, 10);
|
||||
if (*end != 0) {
|
||||
return 0;
|
||||
}
|
||||
if ((port < 1024) || (port > 65535)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (device_addr->ss_family == AF_INET) {
|
||||
struct sockaddr_in *device_addr_in = (struct sockaddr_in *)device_addr;
|
||||
device_addr_in->sin_port = htons((uint16_t)port);
|
||||
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create_multicast_ex((struct sockaddr *)device_addr, hds->dbg);
|
||||
if (!hd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdhomerun_device_selector_add_device(hds, hd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (device_addr->ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *device_addr_in = (struct sockaddr_in6 *)device_addr;
|
||||
device_addr_in->sin6_port = htons((uint16_t)port);
|
||||
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create_multicast_ex((struct sockaddr *)device_addr, hds->dbg);
|
||||
if (!hd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdhomerun_device_selector_add_device(hds, hd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*ptr == '-') {
|
||||
ptr++;
|
||||
|
||||
char *end;
|
||||
unsigned int tuner_index = (unsigned int)strtoul(ptr, &end, 10);
|
||||
if (*end != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create_ex(device_id, (struct sockaddr *)device_addr, tuner_index, hds->dbg);
|
||||
if (!hd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdhomerun_device_selector_add_device(hds, hd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdhomerun_device_selector_load_from_str(struct hdhomerun_device_selector_t *hds, char *device_str)
|
||||
{
|
||||
/*
|
||||
* IP address based device_str.
|
||||
*/
|
||||
unsigned int a[4];
|
||||
if (sscanf(device_str, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]) == 4) {
|
||||
uint32_t ip_addr = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
|
||||
|
||||
/*
|
||||
* Multicast IP address.
|
||||
*/
|
||||
unsigned int port;
|
||||
if (sscanf(device_str, "%u.%u.%u.%u:%u", &a[0], &a[1], &a[2], &a[3], &port) == 5) {
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create_multicast(ip_addr, (uint16_t)port, hds->dbg);
|
||||
if (!hd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdhomerun_device_selector_add_device(hds, hd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* IP address + tuner number.
|
||||
*/
|
||||
unsigned int tuner;
|
||||
if (sscanf(device_str, "%u.%u.%u.%u-%u", &a[0], &a[1], &a[2], &a[3], &tuner) == 5) {
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, tuner, hds->dbg);
|
||||
if (!hd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdhomerun_device_selector_add_device(hds, hd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* IP address only - discover and add tuners.
|
||||
*/
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, ip_addr, HDHOMERUN_DEVICE_ID_WILDCARD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ID based device_str.
|
||||
*/
|
||||
char *end;
|
||||
uint32_t device_id = (uint32_t)strtoul(device_str, &end, 16);
|
||||
if ((end == device_str + 8) && hdhomerun_discover_validate_device_id(device_id)) {
|
||||
/*
|
||||
* IP address + tuner number.
|
||||
*/
|
||||
if (*end == '-') {
|
||||
unsigned int tuner = (unsigned int)strtoul(end + 1, NULL, 10);
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create(device_id, 0, tuner, hds->dbg);
|
||||
if (!hd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdhomerun_device_selector_add_device(hds, hd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ID only - discover and add tuners.
|
||||
*/
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, 0, device_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* DNS based device_str.
|
||||
*/
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
struct addrinfo *sock_info;
|
||||
if (getaddrinfo(device_str, "65001", &hints, &sock_info) != 0) {
|
||||
char str[64];
|
||||
if (!hdhomerun_sprintf(str, str + sizeof(str), "%s", device_str)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr;
|
||||
uint32_t ip_addr = (uint32_t)ntohl(sock_addr->sin_addr.s_addr);
|
||||
freeaddrinfo(sock_info);
|
||||
uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
|
||||
struct sockaddr_storage device_addr;
|
||||
device_addr.ss_family = 0;
|
||||
|
||||
char *ptr = str;
|
||||
bool framed = (*ptr == '[');
|
||||
if (framed) {
|
||||
ptr++;
|
||||
|
||||
char *end = strchr(ptr, ']');
|
||||
if (!end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*end++ = 0;
|
||||
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
return hdhomerun_device_selector_load_from_str_tail(hds, end, device_id, &device_addr);
|
||||
}
|
||||
|
||||
if (ip_addr == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, ip_addr, HDHOMERUN_DEVICE_ID_WILDCARD);
|
||||
char *dash = strchr(ptr, '-');
|
||||
if (dash) {
|
||||
*dash = 0;
|
||||
|
||||
if (hdhomerun_device_selector_load_from_str_parse_device_id(ptr, &device_id)) {
|
||||
*dash = '-';
|
||||
return hdhomerun_device_selector_load_from_str_tail(hds, dash, device_id, &device_addr);
|
||||
}
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
*dash = '-';
|
||||
return hdhomerun_device_selector_load_from_str_tail(hds, dash, device_id, &device_addr);
|
||||
}
|
||||
|
||||
*dash = '-';
|
||||
if (hdhomerun_device_selector_load_from_str_parse_dns(ptr, &device_addr)) {
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, device_id, (struct sockaddr *)&device_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *colon = strchr(ptr, ':');
|
||||
if (colon) {
|
||||
char *second_colon = strchr(colon, ':');
|
||||
if (second_colon) {
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, device_id, (struct sockaddr *)&device_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
*colon = ':';
|
||||
return hdhomerun_device_selector_load_from_str_tail(hds, colon, device_id, &device_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hdhomerun_device_selector_load_from_str_parse_device_id(ptr, &device_id)) {
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, device_id, (struct sockaddr *)&device_addr);
|
||||
}
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, device_id, (struct sockaddr *)&device_addr);
|
||||
}
|
||||
if (hdhomerun_device_selector_load_from_str_parse_dns(ptr, &device_addr)) {
|
||||
return hdhomerun_device_selector_load_from_str_discover(hds, device_id, (struct sockaddr *)&device_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename)
|
||||
|
|
|
@ -130,7 +130,13 @@ static void hdhomerun_discover_sock_add_ipv6(void *arg, uint32_t ifindex, const
|
|||
detected_ip->sin6_port = htons(hdhomerun_discover_get_local_port(ds));
|
||||
|
||||
if (!hdhomerun_sock_bind_ex(dss->sock, (const struct sockaddr *)detected_ip, true)) {
|
||||
hdhomerun_debug_printf(ds->dbg, "discover: failed to bind to local ip (%d)\n", hdhomerun_sock_getlasterror());
|
||||
if (ds->dbg) {
|
||||
int last_error = hdhomerun_sock_getlasterror();
|
||||
char detected_ip_str[64];
|
||||
hdhomerun_sock_sockaddr_to_ip_str(detected_ip_str, (const struct sockaddr *)detected_ip, true);
|
||||
hdhomerun_debug_printf(ds->dbg, "discover: failed to bind to local ip %s (%d)\n", detected_ip_str, last_error);
|
||||
}
|
||||
|
||||
hdhomerun_discover_sock_free(dss);
|
||||
return;
|
||||
}
|
||||
|
@ -183,7 +189,13 @@ static void hdhomerun_discover_sock_add_ipv4(void *arg, uint32_t ifindex, const
|
|||
detected_ip->sin_port = htons(hdhomerun_discover_get_local_port(ds));
|
||||
|
||||
if (!hdhomerun_sock_bind_ex(dss->sock, (const struct sockaddr *)detected_ip, true)) {
|
||||
hdhomerun_debug_printf(ds->dbg, "discover: failed to bind to local ip (%d)\n", hdhomerun_sock_getlasterror());
|
||||
if (ds->dbg) {
|
||||
int last_error = hdhomerun_sock_getlasterror();
|
||||
char detected_ip_str[64];
|
||||
hdhomerun_sock_sockaddr_to_ip_str(detected_ip_str, (const struct sockaddr *)detected_ip, true);
|
||||
hdhomerun_debug_printf(ds->dbg, "discover: failed to bind to local ip %s (%d)\n", detected_ip_str, last_error);
|
||||
}
|
||||
|
||||
hdhomerun_discover_sock_free(dss);
|
||||
return;
|
||||
}
|
||||
|
@ -484,7 +496,7 @@ static inline bool hdhomerun_discover_is_ipv4_autoip(const struct sockaddr *ip_a
|
|||
|
||||
const struct sockaddr_in *sock_addr_in = (const struct sockaddr_in *)ip_addr;
|
||||
uint8_t *addr_bytes = (uint8_t *)&sock_addr_in->sin_addr.s_addr;
|
||||
return (addr_bytes[0] == 0xA9) && (addr_bytes[1] == 0xFE);
|
||||
return (addr_bytes[0] == 169) && (addr_bytes[1] == 254);
|
||||
}
|
||||
|
||||
static inline bool hdhomerun_discover_is_ipv6_localhost(const struct sockaddr *ip_addr)
|
||||
|
@ -496,8 +508,8 @@ static inline bool hdhomerun_discover_is_ipv6_localhost(const struct sockaddr *i
|
|||
const struct sockaddr_in6 *sock_addr_in6 = (const struct sockaddr_in6 *)ip_addr;
|
||||
uint8_t *addr_bytes = (uint8_t *)sock_addr_in6->sin6_addr.s6_addr;
|
||||
|
||||
static uint8_t hdhomerun_discover_ipv6_localhost[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
return (memcmp(addr_bytes, hdhomerun_discover_ipv6_localhost, 16) == 0);
|
||||
static uint8_t hdhomerun_discover_ipv6_localhost_bytes[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
return (memcmp(addr_bytes, hdhomerun_discover_ipv6_localhost_bytes, 16) == 0);
|
||||
}
|
||||
|
||||
static inline bool hdhomerun_discover_is_ipv6_routable(const struct sockaddr *ip_addr)
|
||||
|
@ -576,23 +588,38 @@ static void hdhomerun_discover_send_ipv4_targeted(struct hdhomerun_discover_t *d
|
|||
memcpy(&target_addr_in, target_addr, sizeof(target_addr_in));
|
||||
target_addr_in.sin_port = htons(HDHOMERUN_DISCOVER_UDP_PORT);
|
||||
|
||||
/* ipv4 autoip - send out every interface that has an autoip address */
|
||||
if (hdhomerun_discover_is_ipv4_autoip(target_addr)) {
|
||||
struct hdhomerun_discover_sock_t *dss = default_dss->next;
|
||||
while (dss) {
|
||||
if (!hdhomerun_discover_is_ipv4_autoip((const struct sockaddr *)&dss->local_ip)) {
|
||||
dss = dss->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hdhomerun_discover_send_request(ds, dss, (const struct sockaddr *)&target_addr_in, device_types, device_types_count, device_id)) {
|
||||
dss = dss->next;
|
||||
continue;
|
||||
}
|
||||
uint32_t target_ipv4 = ntohl(target_addr_in.sin_addr.s_addr);
|
||||
bool local_subnet_send = false;
|
||||
|
||||
struct hdhomerun_discover_sock_t *dss = default_dss->next;
|
||||
while (dss) {
|
||||
if (dss->ipv4_subnet_mask == 0) {
|
||||
dss = dss->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr_in *local_ip_in = (struct sockaddr_in *)&dss->local_ip;
|
||||
uint32_t local_ipv4 = ntohl(local_ip_in->sin_addr.s_addr);
|
||||
|
||||
if ((target_ipv4 & dss->ipv4_subnet_mask) != (local_ipv4 & dss->ipv4_subnet_mask)) {
|
||||
dss = dss->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hdhomerun_discover_send_request(ds, dss, (const struct sockaddr *)&target_addr_in, device_types, device_types_count, device_id)) {
|
||||
dss = dss->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
local_subnet_send = true;
|
||||
dss = dss->next;
|
||||
}
|
||||
|
||||
if (local_subnet_send) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hdhomerun_discover_is_ipv4_autoip(target_addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -839,6 +866,60 @@ static void hdhomerun_discover_recv_internal_auth_bin(char **poutput, struct hdh
|
|||
*poutput = str;
|
||||
}
|
||||
|
||||
static void hdhomerun_discover_recv_fixup_tuner_count(struct hdhomerun_discover_t *ds, struct hdhomerun_discover2_device_t *device)
|
||||
{
|
||||
if (!hdhomerun_discover2_device_is_type(device, HDHOMERUN_DEVICE_TYPE_TUNER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device->tuner_count > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (device->device_id >> 20) {
|
||||
case 0x102:
|
||||
device->tuner_count = 1;
|
||||
break;
|
||||
|
||||
case 0x100:
|
||||
case 0x101:
|
||||
case 0x121:
|
||||
device->tuner_count = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hdhomerun_discover_recv_fixup_base_url(struct hdhomerun_discover_t *ds, struct hdhomerun_discover2_device_t *device)
|
||||
{
|
||||
if (!hdhomerun_discover2_device_is_type(device, HDHOMERUN_DEVICE_TYPE_TUNER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct hdhomerun_discover2_device_if_t *device_if = device->if_list;
|
||||
if (device_if->base_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_if->ip_addr.ss_family != AF_INET) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_if->base_url = (char *)malloc(32);
|
||||
if (!device_if->base_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&device_if->ip_addr;
|
||||
uint32_t ip = ntohl(sock_addr_in->sin_addr.s_addr);
|
||||
|
||||
hdhomerun_sprintf(device_if->base_url, device_if->base_url + 32, "http://%u.%u.%u.%u:80",
|
||||
(ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF
|
||||
);
|
||||
}
|
||||
|
||||
static bool hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_pkt_t *rx_pkt, struct hdhomerun_discover2_device_t *device)
|
||||
{
|
||||
uint16_t type;
|
||||
|
@ -926,41 +1007,12 @@ static bool hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, st
|
|||
/*
|
||||
* Fixup for old firmware.
|
||||
*/
|
||||
if (hdhomerun_discover2_device_is_type(device, HDHOMERUN_DEVICE_TYPE_TUNER)) {
|
||||
if (device->tuner_count == 0) {
|
||||
switch (device->device_id >> 20) {
|
||||
case 0x102:
|
||||
device->tuner_count = 1;
|
||||
break;
|
||||
|
||||
case 0x100:
|
||||
case 0x101:
|
||||
case 0x121:
|
||||
device->tuner_count = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device_if->base_url && (device_if->ip_addr.ss_family == AF_INET)) {
|
||||
char *str = (char *)malloc(32);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&device_if->ip_addr;
|
||||
uint32_t ip = ntohl(sock_addr_in->sin_addr.s_addr);
|
||||
|
||||
hdhomerun_sprintf(str, str + 32, "http://%u.%u.%u.%u:80",
|
||||
(ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF
|
||||
);
|
||||
|
||||
device_if->base_url = str;
|
||||
}
|
||||
}
|
||||
hdhomerun_discover_recv_fixup_tuner_count(ds, device);
|
||||
hdhomerun_discover_recv_fixup_base_url(ds, device);
|
||||
|
||||
/*
|
||||
* Success
|
||||
*/
|
||||
device_if->priority = hdhomerun_discover_compute_device_if_priority(device_if);
|
||||
return true;
|
||||
}
|
||||
|
@ -1450,6 +1502,16 @@ bool hdhomerun_discover2_device_if_addr_is_ipv6_linklocal(struct hdhomerun_disco
|
|||
return hdhomerun_discover_is_ipv6_linklocal((const struct sockaddr *)&device_if->ip_addr);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_discover2_device_if_get_ipv6_linklocal_scope_id(struct hdhomerun_discover2_device_if_t *device_if)
|
||||
{
|
||||
if (!hdhomerun_discover_is_ipv6_linklocal((const struct sockaddr *)&device_if->ip_addr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sockaddr_in6 *ip_addr_in6 = (const struct sockaddr_in6 *)&device_if->ip_addr;
|
||||
return ip_addr_in6->sin6_scope_id;
|
||||
}
|
||||
|
||||
void hdhomerun_discover2_device_if_get_ip_addr(struct hdhomerun_discover2_device_if_t *device_if, struct sockaddr_storage *ip_addr)
|
||||
{
|
||||
*ip_addr = device_if->ip_addr;
|
||||
|
|
|
@ -54,10 +54,10 @@ extern LIBHDHOMERUN_API void hdhomerun_discover_destroy(struct hdhomerun_discove
|
|||
* Results 0 when no devices are found.
|
||||
* Returns -1 on error.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover2_find_devices_targeted(struct hdhomerun_discover_t *ds, const struct sockaddr *target_addr, const uint32_t device_types[], size_t device_types_count);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover2_find_devices_broadcast(struct hdhomerun_discover_t *ds, uint32_t flags, uint32_t const device_types[], size_t device_types_count);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover2_find_device_id_targeted(struct hdhomerun_discover_t *ds, const struct sockaddr *target_addr, uint32_t device_id);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover2_find_devices_targeted(struct hdhomerun_discover_t *ds, const struct sockaddr *target_addr, const uint32_t device_types[], size_t device_types_count);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover2_find_device_id_broadcast(struct hdhomerun_discover_t *ds, uint32_t flags, uint32_t device_id);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover2_find_device_id_targeted(struct hdhomerun_discover_t *ds, const struct sockaddr *target_addr, uint32_t device_id);
|
||||
|
||||
/*
|
||||
* Discover result access API.
|
||||
|
@ -86,6 +86,7 @@ extern LIBHDHOMERUN_API const char *hdhomerun_discover2_device_get_device_auth(s
|
|||
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover2_device_if_addr_is_ipv4(struct hdhomerun_discover2_device_if_t *device_if);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover2_device_if_addr_is_ipv6_linklocal(struct hdhomerun_discover2_device_if_t *device_if);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_discover2_device_if_get_ipv6_linklocal_scope_id(struct hdhomerun_discover2_device_if_t *device_if);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_discover2_device_if_get_ip_addr(struct hdhomerun_discover2_device_if_t *device_if, struct sockaddr_storage *ip_addr);
|
||||
extern LIBHDHOMERUN_API const char *hdhomerun_discover2_device_if_get_base_url(struct hdhomerun_discover2_device_if_t *device_if);
|
||||
extern LIBHDHOMERUN_API const char *hdhomerun_discover2_device_if_get_lineup_url(struct hdhomerun_discover2_device_if_t *device_if);
|
||||
|
|
|
@ -66,6 +66,7 @@ extern LIBHDHOMERUN_API void hdhomerun_sock_destroy(struct hdhomerun_sock_t *soc
|
|||
extern LIBHDHOMERUN_API void hdhomerun_sock_set_send_buffer_size(struct hdhomerun_sock_t *sock, size_t size);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_set_recv_buffer_size(struct hdhomerun_sock_t *sock, size_t size);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_set_allow_reuse(struct hdhomerun_sock_t *sock);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_set_ttl(struct hdhomerun_sock_t *sock, uint8_t ttl);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_set_ipv4_onesbcast(struct hdhomerun_sock_t *sock, int v);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_set_ipv6_multicast_ifindex(struct hdhomerun_sock_t *sock, uint32_t ifindex);
|
||||
|
||||
|
|
|
@ -20,9 +20,17 @@
|
|||
|
||||
#include "hdhomerun.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#import <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#if !defined(TARGET_OS_IPHONE)
|
||||
#include <netinet6/in6_var.h>
|
||||
#endif
|
||||
|
||||
#include <ifaddrs.h>
|
||||
|
||||
static uint8_t hdhomerun_local_ip_netmask_to_cidr(uint8_t *subnet_mask, size_t len)
|
||||
|
@ -74,6 +82,11 @@ bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callba
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!hdhomerun_sock_sockaddr_is_addr(ifa->ifa_addr)) {
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int flags = ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_UP | IFF_RUNNING | IFF_MULTICAST);
|
||||
if (flags != (IFF_UP | IFF_RUNNING | IFF_MULTICAST)) {
|
||||
ifa = ifa->ifa_next;
|
||||
|
@ -93,6 +106,7 @@ bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callba
|
|||
}
|
||||
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6) {
|
||||
#if !defined(TARGET_OS_IPHONE)
|
||||
struct in6_ifreq ifr6;
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
|
||||
|
@ -109,7 +123,7 @@ bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callba
|
|||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
uint32_t ifindex = if_nametoindex(ifa->ifa_name);
|
||||
|
||||
struct sockaddr_in6 *netmask_in = (struct sockaddr_in6 *)ifa->ifa_netmask;
|
||||
|
|
|
@ -89,9 +89,7 @@ bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callba
|
|||
/* Local IP address. */
|
||||
struct sockaddr_in ip_addr_in;
|
||||
memcpy(&ip_addr_in, &ifr->ifr_addr, sizeof(ip_addr_in));
|
||||
|
||||
uint32_t ip_addr = ntohl(ip_addr_in.sin_addr.s_addr);
|
||||
if (ip_addr == 0) {
|
||||
if (!hdhomerun_sock_sockaddr_is_addr((const struct sockaddr *)&ip_addr_in)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,11 @@ static void hdhomerun_local_ip_info2_newaddr(int af_sock, struct nlmsghdr *hdr,
|
|||
local_ip.sin_family = AF_INET;
|
||||
memcpy(&local_ip.sin_addr.s_addr, RTA_DATA(rta), 4);
|
||||
|
||||
if (!hdhomerun_sock_sockaddr_is_addr((const struct sockaddr *)&local_ip)) {
|
||||
rta = RTA_NEXT(rta, ifa_payload_length);
|
||||
continue;
|
||||
}
|
||||
|
||||
callback(callback_arg, ifindex, (const struct sockaddr *)&local_ip, cidr);
|
||||
}
|
||||
|
||||
|
@ -96,6 +101,11 @@ static void hdhomerun_local_ip_info2_newaddr(int af_sock, struct nlmsghdr *hdr,
|
|||
local_ip.sin6_family = AF_INET6;
|
||||
memcpy(local_ip.sin6_addr.s6_addr, RTA_DATA(rta), 16);
|
||||
|
||||
if (!hdhomerun_sock_sockaddr_is_addr((const struct sockaddr *)&local_ip)) {
|
||||
rta = RTA_NEXT(rta, ifa_payload_length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((local_ip.sin6_addr.s6_addr[0] == 0xFE) && ((local_ip.sin6_addr.s6_addr[1] & 0xC0) == 0x80)) {
|
||||
local_ip.sin6_scope_id = ifindex;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
struct hdhomerun_sock_t {
|
||||
int sock;
|
||||
int af;
|
||||
uint8_t ttl_set;
|
||||
};
|
||||
|
||||
static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int af, int protocol)
|
||||
|
@ -35,6 +37,8 @@ static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int af, int proto
|
|||
return NULL;
|
||||
}
|
||||
|
||||
sock->af = af;
|
||||
|
||||
/* Create socket. */
|
||||
sock->sock = socket(af, protocol, 0);
|
||||
if (sock->sock == -1) {
|
||||
|
@ -113,6 +117,23 @@ void hdhomerun_sock_set_allow_reuse(struct hdhomerun_sock_t *sock)
|
|||
setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt));
|
||||
}
|
||||
|
||||
void hdhomerun_sock_set_ttl(struct hdhomerun_sock_t *sock, uint8_t ttl)
|
||||
{
|
||||
if (sock->ttl_set == ttl) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sock_opt = (int)(unsigned int)ttl;
|
||||
if (sock->af == AF_INET) {
|
||||
setsockopt(sock->sock, IPPROTO_IP, IP_TTL, (char *)&sock_opt, sizeof(sock_opt));
|
||||
}
|
||||
if (sock->af == AF_INET6) {
|
||||
setsockopt(sock->sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&sock_opt, sizeof(sock_opt));
|
||||
}
|
||||
|
||||
sock->ttl_set = ttl;
|
||||
}
|
||||
|
||||
void hdhomerun_sock_set_ipv4_onesbcast(struct hdhomerun_sock_t *sock, int v)
|
||||
{
|
||||
#if defined(IP_ONESBCAST)
|
||||
|
|
|
@ -25,6 +25,8 @@ struct hdhomerun_sock_t {
|
|||
SOCKET sock;
|
||||
HANDLE event;
|
||||
long events_selected;
|
||||
int af;
|
||||
uint8_t ttl_set;
|
||||
};
|
||||
|
||||
bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callback, void *callback_arg)
|
||||
|
@ -59,6 +61,11 @@ bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callba
|
|||
IP_ADAPTER_ADDRESSES *adapter = adapter_addresses;
|
||||
|
||||
while (adapter) {
|
||||
if (adapter->OperStatus != 1) {
|
||||
adapter = adapter->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((adapter->IfType != MIB_IF_TYPE_ETHERNET) && (adapter->IfType != IF_TYPE_IEEE80211)) {
|
||||
adapter = adapter->Next;
|
||||
continue;
|
||||
|
@ -73,12 +80,16 @@ bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callba
|
|||
|
||||
IP_ADAPTER_UNICAST_ADDRESS *adapter_address = adapter->FirstUnicastAddress;
|
||||
while (adapter_address) {
|
||||
if (adapter_address->Flags & IP_ADAPTER_ADDRESS_TRANSIENT) {
|
||||
struct sockaddr *local_ip = adapter_address->Address.lpSockaddr;
|
||||
if (!hdhomerun_sock_sockaddr_is_addr(local_ip)) {
|
||||
adapter_address = adapter_address->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr *local_ip = adapter_address->Address.lpSockaddr;
|
||||
if (adapter_address->Flags & IP_ADAPTER_ADDRESS_TRANSIENT) {
|
||||
adapter_address = adapter_address->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((local_ip->sa_family == AF_INET6) && (adapter_address->ValidLifetime != 0xFFFFFFFF)) {
|
||||
adapter_address = adapter_address->Next;
|
||||
|
@ -105,6 +116,8 @@ static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int af, int proto
|
|||
return NULL;
|
||||
}
|
||||
|
||||
sock->af = af;
|
||||
|
||||
/* Create socket. */
|
||||
sock->sock = socket(af, protocol, 0);
|
||||
if (sock->sock == INVALID_SOCKET) {
|
||||
|
@ -189,6 +202,23 @@ void hdhomerun_sock_set_allow_reuse(struct hdhomerun_sock_t *sock)
|
|||
setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt));
|
||||
}
|
||||
|
||||
void hdhomerun_sock_set_ttl(struct hdhomerun_sock_t *sock, uint8_t ttl)
|
||||
{
|
||||
if (sock->ttl_set == ttl) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sock_opt = (int)(unsigned int)ttl;
|
||||
if (sock->af == AF_INET) {
|
||||
setsockopt(sock->sock, IPPROTO_IP, IP_TTL, (char *)&sock_opt, sizeof(sock_opt));
|
||||
}
|
||||
if (sock->af == AF_INET6) {
|
||||
setsockopt(sock->sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&sock_opt, sizeof(sock_opt));
|
||||
}
|
||||
|
||||
sock->ttl_set = ttl;
|
||||
}
|
||||
|
||||
void hdhomerun_sock_set_ipv4_onesbcast(struct hdhomerun_sock_t *sock, int v)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue