mirror of
https://github.com/Silicondust/libhdhomerun
synced 2025-07-06 04:52:19 -07:00
IPv6 support
This commit is contained in:
parent
7d4e2d34ed
commit
0ea5574fa5
19 changed files with 3527 additions and 1098 deletions
85
Makefile
85
Makefile
|
@ -1,4 +1,31 @@
|
|||
|
||||
ifneq ($(OS),Windows_NT)
|
||||
OS := $(shell uname -s)
|
||||
endif
|
||||
|
||||
CC := $(CROSS_COMPILE)gcc
|
||||
STRIP := $(CROSS_COMPILE)strip
|
||||
|
||||
CFLAGS += -O2 -Wall -Wextra -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith -Wno-unused-parameter
|
||||
LDFLAGS += -lpthread
|
||||
SHARED = -shared -Wl,-soname,libhdhomerun$(LIBEXT)
|
||||
|
||||
IF_DETECT := getifaddrs
|
||||
BINEXT :=
|
||||
LIBEXT := .so
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
IF_DETECT := netdevice
|
||||
BINEXT := .exe
|
||||
LIBEXT := .dll
|
||||
LDFLAGS += -liphlpapi
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Linux)
|
||||
IF_DETECT := netlink
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
LIBSRCS += hdhomerun_channels.c
|
||||
LIBSRCS += hdhomerun_channelscan.c
|
||||
LIBSRCS += hdhomerun_control.c
|
||||
|
@ -8,35 +35,39 @@ LIBSRCS += hdhomerun_device_selector.c
|
|||
LIBSRCS += hdhomerun_discover.c
|
||||
LIBSRCS += hdhomerun_os_posix.c
|
||||
LIBSRCS += hdhomerun_pkt.c
|
||||
LIBSRCS += hdhomerun_sock.c
|
||||
LIBSRCS += hdhomerun_sock_posix.c
|
||||
LIBSRCS += hdhomerun_sock_$(IF_DETECT).c
|
||||
LIBSRCS += hdhomerun_video.c
|
||||
|
||||
CC := $(CROSS_COMPILE)gcc
|
||||
STRIP := $(CROSS_COMPILE)strip
|
||||
|
||||
CFLAGS += -O2 -Wall -Wextra -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith -Wno-unused-parameter
|
||||
LDFLAGS += -lpthread
|
||||
SHARED = -shared -Wl,-soname,libhdhomerun$(LIBEXT)
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
BINEXT := .exe
|
||||
LIBEXT := .dll
|
||||
LDFLAGS += -liphlpapi
|
||||
else
|
||||
OS := $(shell uname -s)
|
||||
LIBEXT := .so
|
||||
ifeq ($(OS),Linux)
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
ifeq ($(OS),SunOS)
|
||||
LDFLAGS += -lsocket
|
||||
endif
|
||||
ifeq ($(OS),Darwin)
|
||||
CFLAGS += -arch x86_64
|
||||
LIBEXT := .dylib
|
||||
SHARED := -dynamiclib -install_name libhdhomerun$(LIBEXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
TARGET_X64 := -target x86_64-apple-macos10.11
|
||||
TARGET_ARM64 := -target arm64-apple-macos11
|
||||
|
||||
all : hdhomerun_config libhdhomerun.dylib
|
||||
|
||||
hdhomerun_config_x64 : hdhomerun_config.c $(LIBSRCS)
|
||||
$(CC) $(TARGET_X64) $(CFLAGS) $+ $(LDFLAGS) -o $@
|
||||
$(STRIP) $@
|
||||
|
||||
hdhomerun_config_arm64 : hdhomerun_config.c $(LIBSRCS)
|
||||
$(CC) $(TARGET_ARM64) $(CFLAGS) $+ $(LDFLAGS) -o $@
|
||||
$(STRIP) $@
|
||||
|
||||
hdhomerun_config : hdhomerun_config_x64 hdhomerun_config_arm64
|
||||
lipo -create -output hdhomerun_config hdhomerun_config_x64 hdhomerun_config_arm64
|
||||
|
||||
libhdhomerun_x64.dylib : $(LIBSRCS)
|
||||
$(CC) $(TARGET_X64) $(CFLAGS) -DDLL_EXPORT -fPIC -dynamiclib $+ $(LDFLAGS) -o $@
|
||||
|
||||
libhdhomerun_arm64.dylib : $(LIBSRCS)
|
||||
$(CC) $(TARGET_ARM64) $(CFLAGS) -DDLL_EXPORT -fPIC -dynamiclib $+ $(LDFLAGS) -o $@
|
||||
|
||||
libhdhomerun.dylib : libhdhomerun_x64.dylib libhdhomerun_arm64.dylib
|
||||
lipo -create -output libhdhomerun.dylib libhdhomerun_x64.dylib libhdhomerun_arm64.dylib
|
||||
|
||||
else
|
||||
|
||||
all : hdhomerun_config$(BINEXT) libhdhomerun$(LIBEXT)
|
||||
|
||||
|
@ -45,7 +76,9 @@ hdhomerun_config$(BINEXT) : hdhomerun_config.c $(LIBSRCS)
|
|||
$(STRIP) $@
|
||||
|
||||
libhdhomerun$(LIBEXT) : $(LIBSRCS)
|
||||
$(CC) $(CFLAGS) -fPIC -DDLL_EXPORT $(SHARED) $+ $(LDFLAGS) -o $@
|
||||
$(CC) $(CFLAGS) -DDLL_EXPORT -fPIC $(SHARED) $+ $(LDFLAGS) -o $@
|
||||
|
||||
endif
|
||||
|
||||
clean :
|
||||
-rm -f hdhomerun_config$(BINEXT)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright © 2005-2017 Silicondust USA Inc. <www.silicondust.com>.
|
||||
Copyright © 2005-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
|
||||
This library implements the libhdhomerun protocol for use with Silicondust HDHomeRun TV tuners.
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_config.c
|
||||
*
|
||||
* Copyright © 2006-2017 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -27,7 +27,7 @@ struct hdhomerun_device_t *hd;
|
|||
static int help(void)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf("\t%s discover\n", appname);
|
||||
printf("\t%s discover [-4] [-6] [--dedupe] [<ip>]\n", appname);
|
||||
printf("\t%s <id> get help\n", appname);
|
||||
printf("\t%s <id> get <item>\n", appname);
|
||||
printf("\t%s <id> set <item> <value>\n", appname);
|
||||
|
@ -69,59 +69,102 @@ static bool contains(const char *arg, const char *cmpstr)
|
|||
return false;
|
||||
}
|
||||
|
||||
static uint32_t parse_ip_addr(const char *str)
|
||||
static int discover_print(int argc, char *argv[])
|
||||
{
|
||||
unsigned int a[4];
|
||||
if (sscanf(str, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]) != 4) {
|
||||
return 0;
|
||||
}
|
||||
const char *target_ip_str = NULL;
|
||||
uint32_t flags = 0;
|
||||
bool dedupe = false;
|
||||
|
||||
return (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
|
||||
}
|
||||
|
||||
static int discover_print(char *target_ip_str)
|
||||
{
|
||||
uint32_t target_ip = 0;
|
||||
if (target_ip_str) {
|
||||
target_ip = parse_ip_addr(target_ip_str);
|
||||
if (target_ip == 0) {
|
||||
fprintf(stderr, "invalid ip address: %s\n", target_ip_str);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct hdhomerun_discover_device_t result_list[64];
|
||||
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;
|
||||
}
|
||||
|
||||
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++;
|
||||
while (argc--) {
|
||||
char *param = *argv++;
|
||||
if (param[0] != '-') {
|
||||
target_ip_str = param;
|
||||
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++;
|
||||
if (contains(param, "-4")) {
|
||||
flags |= HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL;
|
||||
continue;
|
||||
}
|
||||
if (contains(param, "-6")) {
|
||||
flags |= HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL | HDHOMERUN_DISCOVER_FLAGS_IPV6_LINKLOCAL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (valid_count == 0) {
|
||||
if (contains(param, "dedupe")) {
|
||||
dedupe = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags == 0) {
|
||||
flags = HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL | HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL | HDHOMERUN_DISCOVER_FLAGS_IPV6_LINKLOCAL;
|
||||
}
|
||||
|
||||
struct hdhomerun_discover_t *ds = hdhomerun_discover_create(NULL);
|
||||
if (!ds) {
|
||||
fprintf(stderr, "resource error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Most applications will specify a list of specific types rather than wildcard */
|
||||
uint32_t device_types[1];
|
||||
device_types[0] = HDHOMERUN_DEVICE_TYPE_WILDCARD;
|
||||
|
||||
int ret;
|
||||
if (target_ip_str) {
|
||||
struct sockaddr_storage target_addr;
|
||||
if (!hdhomerun_sock_ip_str_to_sockaddr(target_ip_str , &target_addr)) {
|
||||
fprintf(stderr, "invalid ip address: %s\n", target_ip_str);
|
||||
hdhomerun_discover_destroy(ds);
|
||||
return -1;
|
||||
}
|
||||
ret = hdhomerun_discover2_find_devices_targeted(ds, (struct sockaddr *)&target_addr, device_types, 1);
|
||||
} else {
|
||||
ret = hdhomerun_discover2_find_devices_broadcast(ds, flags, device_types, 1);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error sending discover request\n");
|
||||
hdhomerun_discover_destroy(ds);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
printf("no devices found\n");
|
||||
hdhomerun_discover_destroy(ds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return valid_count;
|
||||
struct hdhomerun_discover2_device_t *device = hdhomerun_discover2_iter_device_first(ds);
|
||||
while (device) {
|
||||
uint32_t device_id = hdhomerun_discover2_device_get_device_id(device);
|
||||
if (device_id == 0) {
|
||||
device = hdhomerun_discover2_iter_device_next(device);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct hdhomerun_discover2_device_if_t *device_if = hdhomerun_discover2_iter_device_if_first(device);
|
||||
while (device_if) {
|
||||
struct sockaddr_storage ip_addr;
|
||||
hdhomerun_discover2_device_if_get_ip_addr(device_if, &ip_addr);
|
||||
|
||||
char ip_str[64];
|
||||
hdhomerun_sock_sockaddr_to_ip_str(ip_str, (struct sockaddr *)&ip_addr, true);
|
||||
printf("hdhomerun device %08X found at %s\n", device_id, ip_str);
|
||||
|
||||
if (dedupe) {
|
||||
break;
|
||||
}
|
||||
|
||||
device_if = hdhomerun_discover2_iter_device_if_next(device_if);
|
||||
}
|
||||
|
||||
device = hdhomerun_discover2_iter_device_next(device);
|
||||
}
|
||||
|
||||
hdhomerun_discover_destroy(ds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cmd_get(const char *item)
|
||||
|
@ -632,7 +675,7 @@ static int main_internal(int argc, char *argv[])
|
|||
/* Initialize network socket support. */
|
||||
WORD wVersionRequested = MAKEWORD(2, 0);
|
||||
WSADATA wsaData;
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
(void)WSAStartup(wVersionRequested, &wsaData);
|
||||
#endif
|
||||
|
||||
extract_appname(argv[0]);
|
||||
|
@ -648,11 +691,7 @@ static int main_internal(int argc, char *argv[])
|
|||
return help();
|
||||
}
|
||||
if (contains(id_str, "discover")) {
|
||||
if (argc < 1) {
|
||||
return discover_print(NULL);
|
||||
} else {
|
||||
return discover_print(argv[0]);
|
||||
}
|
||||
return discover_print(argc, argv);
|
||||
}
|
||||
|
||||
/* Device object. */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_control.c
|
||||
*
|
||||
* Copyright © 2006-2016 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -27,9 +27,9 @@
|
|||
|
||||
struct hdhomerun_control_sock_t {
|
||||
uint32_t desired_device_id;
|
||||
uint32_t desired_device_ip;
|
||||
uint32_t actual_device_id;
|
||||
uint32_t actual_device_ip;
|
||||
struct sockaddr_storage desired_device_addr;
|
||||
struct sockaddr_storage actual_device_addr;
|
||||
struct hdhomerun_sock_t *sock;
|
||||
struct hdhomerun_debug_t *dbg;
|
||||
struct hdhomerun_pkt_t tx_pkt;
|
||||
|
@ -47,16 +47,36 @@ static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs)
|
|||
}
|
||||
|
||||
void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip)
|
||||
{
|
||||
struct sockaddr_in device_addr;
|
||||
memset(&device_addr, 0, sizeof(device_addr));
|
||||
device_addr.sin_family = AF_INET;
|
||||
device_addr.sin_addr.s_addr = htonl(device_ip);
|
||||
|
||||
hdhomerun_control_set_device_ex(cs, device_id, (const struct sockaddr *)&device_addr);
|
||||
}
|
||||
|
||||
void hdhomerun_control_set_device_ex(struct hdhomerun_control_sock_t *cs, uint32_t device_id, const struct sockaddr *device_addr)
|
||||
{
|
||||
hdhomerun_control_close_sock(cs);
|
||||
|
||||
cs->desired_device_id = device_id;
|
||||
cs->desired_device_ip = device_ip;
|
||||
cs->actual_device_id = 0;
|
||||
cs->actual_device_ip = 0;
|
||||
hdhomerun_sock_sockaddr_copy(&cs->desired_device_addr, device_addr);
|
||||
memset(&cs->actual_device_addr, 0, sizeof(cs->actual_device_addr));
|
||||
}
|
||||
|
||||
struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
struct sockaddr_in device_addr;
|
||||
memset(&device_addr, 0, sizeof(device_addr));
|
||||
device_addr.sin_family = AF_INET;
|
||||
device_addr.sin_addr.s_addr = htonl(device_ip);
|
||||
|
||||
return hdhomerun_control_create_ex(device_id, (const struct sockaddr *)&device_addr, dbg);
|
||||
}
|
||||
|
||||
struct hdhomerun_control_sock_t *hdhomerun_control_create_ex(uint32_t device_id, const struct sockaddr *device_addr, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
struct hdhomerun_control_sock_t *cs = (struct hdhomerun_control_sock_t *)calloc(1, sizeof(struct hdhomerun_control_sock_t));
|
||||
if (!cs) {
|
||||
|
@ -65,7 +85,7 @@ struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, ui
|
|||
}
|
||||
|
||||
cs->dbg = dbg;
|
||||
hdhomerun_control_set_device(cs, device_id, device_ip);
|
||||
hdhomerun_control_set_device_ex(cs, device_id, device_addr);
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
@ -76,39 +96,82 @@ void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs)
|
|||
free(cs);
|
||||
}
|
||||
|
||||
static bool hdhomerun_control_connect_sock_discover(struct hdhomerun_control_sock_t *cs)
|
||||
{
|
||||
struct hdhomerun_discover_t *ds = hdhomerun_discover_create(NULL);
|
||||
if (!ds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t device_types[1];
|
||||
device_types[0] = HDHOMERUN_DEVICE_TYPE_WILDCARD;
|
||||
|
||||
uint32_t device_id = cs->desired_device_id;
|
||||
if (device_id == 0) {
|
||||
device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
|
||||
}
|
||||
|
||||
int ret;
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&cs->desired_device_addr)) {
|
||||
if (device_id == HDHOMERUN_DEVICE_ID_WILDCARD) {
|
||||
ret = hdhomerun_discover2_find_devices_targeted(ds, (struct sockaddr *)&cs->desired_device_addr, device_types, 1);
|
||||
} else {
|
||||
ret = hdhomerun_discover2_find_device_id_targeted(ds, (struct sockaddr *)&cs->desired_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(ds, flags, device_types, 1);
|
||||
} else {
|
||||
ret = hdhomerun_discover2_find_device_id_broadcast(ds, flags, device_id);
|
||||
}
|
||||
}
|
||||
if (ret <= 0) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: device not found\n");
|
||||
hdhomerun_discover_destroy(ds);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct hdhomerun_discover2_device_t *device = hdhomerun_discover2_iter_device_first(ds);
|
||||
cs->actual_device_id = hdhomerun_discover2_device_get_device_id(device);
|
||||
|
||||
struct hdhomerun_discover2_device_if_t *device_if = hdhomerun_discover2_iter_device_if_first(device);
|
||||
hdhomerun_discover2_device_if_get_ip_addr(device_if, &cs->actual_device_addr);
|
||||
|
||||
hdhomerun_discover_destroy(ds);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs)
|
||||
{
|
||||
if (cs->sock) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((cs->desired_device_id == 0) && (cs->desired_device_ip == 0)) {
|
||||
if ((cs->desired_device_id == 0) && !hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&cs->desired_device_addr)) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: no device specified\n");
|
||||
return false;
|
||||
}
|
||||
if (hdhomerun_discover_is_ip_multicast(cs->desired_device_ip)) {
|
||||
if (hdhomerun_discover_is_ip_multicast_ex((struct sockaddr *)&cs->desired_device_addr)) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: cannot use multicast ip address for device operations\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find device. */
|
||||
struct hdhomerun_discover_device_t result;
|
||||
if (hdhomerun_discover_find_devices_custom_v2(cs->desired_device_ip, HDHOMERUN_DEVICE_TYPE_WILDCARD, cs->desired_device_id, &result, 1) <= 0) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: device not found\n");
|
||||
if (!hdhomerun_control_connect_sock_discover(cs)) {
|
||||
return false;
|
||||
}
|
||||
cs->actual_device_ip = result.ip_addr;
|
||||
cs->actual_device_id = result.device_id;
|
||||
|
||||
/* Create socket. */
|
||||
cs->sock = hdhomerun_sock_create_tcp();
|
||||
cs->sock = hdhomerun_sock_create_tcp_ex(cs->actual_device_addr.ss_family);
|
||||
if (!cs->sock) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to create socket (%d)\n", hdhomerun_sock_getlasterror());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initiate connection. */
|
||||
if (!hdhomerun_sock_connect(cs->sock, cs->actual_device_ip, HDHOMERUN_CONTROL_TCP_PORT, HDHOMERUN_CONTROL_CONNECT_TIMEOUT)) {
|
||||
hdhomerun_sock_sockaddr_set_port((struct sockaddr *)&cs->actual_device_addr, HDHOMERUN_CONTROL_TCP_PORT);
|
||||
if (!hdhomerun_sock_connect_ex(cs->sock, (struct sockaddr *)&cs->actual_device_addr, HDHOMERUN_CONTROL_CONNECT_TIMEOUT)) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to connect (%d)\n", hdhomerun_sock_getlasterror());
|
||||
hdhomerun_control_close_sock(cs);
|
||||
return false;
|
||||
|
@ -135,7 +198,24 @@ uint32_t hdhomerun_control_get_device_ip(struct hdhomerun_control_sock_t *cs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return cs->actual_device_ip;
|
||||
if (cs->actual_device_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in *actual_device_addr_in = (struct sockaddr_in *)&cs->actual_device_addr;
|
||||
return ntohl(actual_device_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_control_get_device_addr(struct hdhomerun_control_sock_t *cs, struct sockaddr_storage *result)
|
||||
{
|
||||
if (!hdhomerun_control_connect_sock(cs)) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_device_ip: connect failed\n");
|
||||
memset(result, 0, sizeof(struct sockaddr_storage));
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = cs->actual_device_addr;
|
||||
return hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)result);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock_t *cs)
|
||||
|
@ -145,23 +225,47 @@ uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock
|
|||
|
||||
uint32_t hdhomerun_control_get_device_ip_requested(struct hdhomerun_control_sock_t *cs)
|
||||
{
|
||||
return cs->desired_device_ip;
|
||||
if (cs->desired_device_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in *desired_device_addr_in = (struct sockaddr_in *)&cs->desired_device_addr;
|
||||
return ntohl(desired_device_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_control_get_device_addr_requested(struct hdhomerun_control_sock_t *cs, struct sockaddr_storage *result)
|
||||
{
|
||||
*result = cs->desired_device_addr;
|
||||
return hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)result);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs)
|
||||
{
|
||||
struct sockaddr_storage local_addr;
|
||||
if (!hdhomerun_control_get_local_addr_ex(cs, &local_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (local_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in *local_addr_in = (struct sockaddr_in *)&local_addr;
|
||||
return ntohl(local_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_control_get_local_addr_ex(struct hdhomerun_control_sock_t *cs, struct sockaddr_storage *result)
|
||||
{
|
||||
if (!hdhomerun_control_connect_sock(cs)) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: connect failed\n");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t addr = hdhomerun_sock_getsockname_addr(cs->sock);
|
||||
if (addr == 0) {
|
||||
if (!hdhomerun_sock_getsockname_addr_ex(cs->sock, result)) {
|
||||
hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: getsockname failed (%d)\n", hdhomerun_sock_getlasterror());
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_control.h
|
||||
*
|
||||
* Copyright © 2006-2015 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -38,6 +38,7 @@ struct hdhomerun_control_sock_t;
|
|||
* When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_control_sock_t *hdhomerun_control_create_ex(uint32_t device_id, const struct sockaddr *device_addr, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs);
|
||||
|
||||
/*
|
||||
|
@ -47,10 +48,13 @@ extern LIBHDHOMERUN_API void hdhomerun_control_destroy(struct hdhomerun_control_
|
|||
*/
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_id(struct hdhomerun_control_sock_t *cs);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_ip(struct hdhomerun_control_sock_t *cs);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_control_get_device_addr(struct hdhomerun_control_sock_t *cs, struct sockaddr_storage *result);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock_t *cs);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_ip_requested(struct hdhomerun_control_sock_t *cs);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_control_get_device_addr_requested(struct hdhomerun_control_sock_t *cs, struct sockaddr_storage *result);
|
||||
|
||||
extern LIBHDHOMERUN_API void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_control_set_device_ex(struct hdhomerun_control_sock_t *cs, uint32_t device_id, const struct sockaddr *device_addr);
|
||||
|
||||
/*
|
||||
* Get the local machine IP address used when communicating with the device.
|
||||
|
@ -60,6 +64,7 @@ extern LIBHDHOMERUN_API void hdhomerun_control_set_device(struct hdhomerun_contr
|
|||
* Returns 32-bit IP address with native endianness, or 0 on error.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_control_get_local_addr_ex(struct hdhomerun_control_sock_t *cs, struct sockaddr_storage *result);
|
||||
|
||||
/*
|
||||
* Low-level communication.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_device.c
|
||||
*
|
||||
* Copyright © 2006-2015 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -25,8 +25,7 @@ struct hdhomerun_device_t {
|
|||
struct hdhomerun_video_sock_t *vs;
|
||||
struct hdhomerun_debug_t *dbg;
|
||||
struct hdhomerun_channelscan_t *scan;
|
||||
uint32_t multicast_ip;
|
||||
uint16_t multicast_port;
|
||||
struct sockaddr_storage multicast_addr;
|
||||
uint32_t device_id;
|
||||
unsigned int tuner;
|
||||
uint32_t lockkey;
|
||||
|
@ -36,13 +35,23 @@ struct hdhomerun_device_t {
|
|||
|
||||
int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip)
|
||||
{
|
||||
if ((device_id == 0) && (device_ip == 0)) {
|
||||
struct sockaddr_in device_addr;
|
||||
memset(&device_addr, 0, sizeof(device_addr));
|
||||
device_addr.sin_family = AF_INET;
|
||||
device_addr.sin_addr.s_addr = htonl(device_ip);
|
||||
|
||||
return hdhomerun_device_set_device_ex(hd, device_id, (const struct sockaddr *)&device_addr);
|
||||
}
|
||||
|
||||
int hdhomerun_device_set_device_ex(struct hdhomerun_device_t *hd, uint32_t device_id, const struct sockaddr *device_addr)
|
||||
{
|
||||
if ((device_id == 0) && !hdhomerun_sock_sockaddr_is_addr(device_addr)) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: device not specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdhomerun_discover_is_ip_multicast(device_ip)) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: invalid address %08X\n", (unsigned int)device_ip);
|
||||
if (hdhomerun_discover_is_ip_multicast_ex(device_addr)) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: invalid address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -54,14 +63,13 @@ int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_i
|
|||
}
|
||||
}
|
||||
|
||||
hdhomerun_control_set_device(hd->cs, device_id, device_ip);
|
||||
hdhomerun_control_set_device_ex(hd->cs, device_id, device_addr);
|
||||
|
||||
if ((device_id == 0) || (device_id == HDHOMERUN_DEVICE_ID_WILDCARD)) {
|
||||
device_id = hdhomerun_control_get_device_id(hd->cs);
|
||||
}
|
||||
|
||||
hd->multicast_ip = 0;
|
||||
hd->multicast_port = 0;
|
||||
memset(&hd->multicast_addr, 0, sizeof(hd->multicast_addr));
|
||||
hd->device_id = device_id;
|
||||
hd->tuner = 0;
|
||||
hd->lockkey = 0;
|
||||
|
@ -74,11 +82,23 @@ int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_i
|
|||
|
||||
int hdhomerun_device_set_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip, uint16_t multicast_port)
|
||||
{
|
||||
if (!hdhomerun_discover_is_ip_multicast(multicast_ip)) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device_multicast: invalid address %08X\n", (unsigned int)multicast_ip);
|
||||
struct sockaddr_in multicast_addr;
|
||||
memset(&multicast_addr, 0, sizeof(multicast_addr));
|
||||
multicast_addr.sin_family = AF_INET;
|
||||
multicast_addr.sin_addr.s_addr = htonl(multicast_ip);
|
||||
multicast_addr.sin_port = htons(multicast_port);
|
||||
|
||||
return hdhomerun_device_set_multicast_ex(hd, (const struct sockaddr *)&multicast_addr);
|
||||
}
|
||||
|
||||
int hdhomerun_device_set_multicast_ex(struct hdhomerun_device_t *hd, const struct sockaddr *multicast_addr)
|
||||
{
|
||||
if (!hdhomerun_discover_is_ip_multicast_ex(multicast_addr)) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device_multicast: invalid address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t multicast_port = hdhomerun_sock_sockaddr_get_port(multicast_addr);
|
||||
if (multicast_port == 0) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device_multicast: invalid port %u\n", (unsigned int)multicast_port);
|
||||
return -1;
|
||||
|
@ -89,14 +109,12 @@ int hdhomerun_device_set_multicast(struct hdhomerun_device_t *hd, uint32_t multi
|
|||
hd->cs = NULL;
|
||||
}
|
||||
|
||||
hd->multicast_ip = multicast_ip;
|
||||
hd->multicast_port = multicast_port;
|
||||
hdhomerun_sock_sockaddr_copy(&hd->multicast_addr, multicast_addr);
|
||||
hd->device_id = 0;
|
||||
hd->tuner = 0;
|
||||
hd->lockkey = 0;
|
||||
|
||||
unsigned int ip = multicast_ip;
|
||||
hdhomerun_sprintf(hd->name, hd->name + sizeof(hd->name), "%u.%u.%u.%u:%u", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF, (unsigned int)multicast_port);
|
||||
hdhomerun_sprintf(hd->name, hd->name + sizeof(hd->name), "multicast:%u", (unsigned int)multicast_port);
|
||||
hdhomerun_sprintf(hd->model, hd->model + sizeof(hd->model), "multicast");
|
||||
|
||||
return 1;
|
||||
|
@ -104,7 +122,7 @@ int hdhomerun_device_set_multicast(struct hdhomerun_device_t *hd, uint32_t multi
|
|||
|
||||
int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
if (tuner != 0) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner: tuner cannot be specified in multicast mode\n");
|
||||
return -1;
|
||||
|
@ -148,16 +166,30 @@ static struct hdhomerun_device_t *hdhomerun_device_create_internal(struct hdhome
|
|||
|
||||
struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
struct sockaddr_in device_addr;
|
||||
memset(&device_addr, 0, sizeof(device_addr));
|
||||
device_addr.sin_family = AF_INET;
|
||||
device_addr.sin_addr.s_addr = htonl(device_ip);
|
||||
|
||||
return hdhomerun_device_create_ex(device_id, (const struct sockaddr *)&device_addr, tuner, dbg);
|
||||
}
|
||||
|
||||
struct hdhomerun_device_t *hdhomerun_device_create_ex(uint32_t device_id, const struct sockaddr *device_addr, unsigned int tuner, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
if ((device_id != 0) && !hdhomerun_discover_validate_device_id(device_id)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create_internal(dbg);
|
||||
if (!hd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((device_id == 0) && (device_ip == 0) && (tuner == 0)) {
|
||||
if ((device_id == 0) && !hdhomerun_sock_sockaddr_is_addr(device_addr) && (tuner == 0)) {
|
||||
return hd;
|
||||
}
|
||||
|
||||
if (hdhomerun_device_set_device(hd, device_id, device_ip) <= 0) {
|
||||
if (hdhomerun_device_set_device_ex(hd, device_id, device_addr) <= 0) {
|
||||
free(hd);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -170,13 +202,24 @@ struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t
|
|||
}
|
||||
|
||||
struct hdhomerun_device_t *hdhomerun_device_create_multicast(uint32_t multicast_ip, uint16_t multicast_port, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
struct sockaddr_in multicast_addr;
|
||||
memset(&multicast_addr, 0, sizeof(multicast_addr));
|
||||
multicast_addr.sin_family = AF_INET;
|
||||
multicast_addr.sin_addr.s_addr = htonl(multicast_ip);
|
||||
multicast_addr.sin_port = htons(multicast_port);
|
||||
|
||||
return hdhomerun_device_create_multicast_ex((const struct sockaddr *)&multicast_addr, dbg);
|
||||
}
|
||||
|
||||
struct hdhomerun_device_t *hdhomerun_device_create_multicast_ex(const struct sockaddr *multicast_addr, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
struct hdhomerun_device_t *hd = hdhomerun_device_create_internal(dbg);
|
||||
if (!hd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hdhomerun_device_set_multicast(hd, multicast_ip, multicast_port) <= 0) {
|
||||
if (hdhomerun_device_set_multicast_ex(hd, multicast_addr) <= 0) {
|
||||
free(hd);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -201,80 +244,186 @@ void hdhomerun_device_destroy(struct hdhomerun_device_t *hd)
|
|||
free(hd);
|
||||
}
|
||||
|
||||
static bool hdhomerun_device_create_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_create_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 struct hdhomerun_device_t *hdhomerun_device_create_from_str_tail(const char *tail, uint32_t device_id, struct sockaddr_storage *device_addr, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
const char *ptr = tail;
|
||||
if (*ptr == 0) {
|
||||
return hdhomerun_device_create_ex(device_id, (struct sockaddr *)device_addr, 0, dbg);
|
||||
}
|
||||
|
||||
if (*ptr == ':') {
|
||||
ptr++;
|
||||
|
||||
char *end;
|
||||
unsigned long port = strtoul(ptr + 1, &end, 10);
|
||||
if (*end != 0) {
|
||||
return NULL;
|
||||
}
|
||||
if ((port < 1024) || (port > 65535)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
return hdhomerun_device_create_multicast_ex((struct sockaddr *)device_addr, dbg);
|
||||
}
|
||||
|
||||
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);
|
||||
return hdhomerun_device_create_multicast_ex((struct sockaddr *)device_addr, dbg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*ptr == '-') {
|
||||
ptr++;
|
||||
|
||||
char *end;
|
||||
unsigned int tuner_index = (unsigned int)strtoul(ptr, &end, 10);
|
||||
if (*end != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hdhomerun_device_create_ex(device_id, (struct sockaddr *)device_addr, tuner_index, dbg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
/*
|
||||
* 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) {
|
||||
return hdhomerun_device_create_multicast(ip_addr, (uint16_t)port, dbg);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, tuner, dbg);
|
||||
}
|
||||
|
||||
/*
|
||||
* IP address only.
|
||||
*/
|
||||
return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, 0, dbg);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
return hdhomerun_device_create(device_id, 0, tuner, dbg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ID only.
|
||||
*/
|
||||
return hdhomerun_device_create(device_id, 0, 0, dbg);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (ip_addr == 0) {
|
||||
char *ptr = str;
|
||||
bool framed = (*ptr == '[');
|
||||
if (framed) {
|
||||
ptr++;
|
||||
|
||||
char *end = strchr(ptr, ']');
|
||||
if (!end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, 0, dbg);
|
||||
*end++ = 0;
|
||||
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
return hdhomerun_device_create_from_str_tail(end, device_id, &device_addr, dbg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *dash = strchr(ptr, '-');
|
||||
if (dash) {
|
||||
*dash = 0;
|
||||
|
||||
if (hdhomerun_device_create_from_str_parse_device_id(ptr, &device_id)) {
|
||||
*dash = '-';
|
||||
return hdhomerun_device_create_from_str_tail(dash, device_id, &device_addr, dbg);
|
||||
}
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
*dash = '-';
|
||||
return hdhomerun_device_create_from_str_tail(dash, device_id, &device_addr, dbg);
|
||||
}
|
||||
|
||||
*dash = '-';
|
||||
if (hdhomerun_device_create_from_str_parse_dns(ptr, &device_addr)) {
|
||||
return hdhomerun_device_create_ex(device_id, (struct sockaddr *)&device_addr, 0, dbg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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_create_ex(device_id, (struct sockaddr *)&device_addr, 0, dbg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
*colon = ':';
|
||||
return hdhomerun_device_create_from_str_tail(colon, device_id, &device_addr, dbg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hdhomerun_device_create_from_str_parse_device_id(ptr, &device_id)) {
|
||||
return hdhomerun_device_create_ex(device_id, (struct sockaddr *)&device_addr, 0, dbg);
|
||||
}
|
||||
if (hdhomerun_sock_ip_str_to_sockaddr(ptr, &device_addr)) {
|
||||
return hdhomerun_device_create_ex(device_id, (struct sockaddr *)&device_addr, 0, dbg);
|
||||
}
|
||||
if (hdhomerun_device_create_from_str_parse_dns(ptr, &device_addr)) {
|
||||
return hdhomerun_device_create_ex(device_id, (struct sockaddr *)&device_addr, 0, dbg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd)
|
||||
|
@ -289,38 +438,73 @@ uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd)
|
|||
|
||||
uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
return hd->multicast_ip;
|
||||
struct sockaddr_storage device_addr;
|
||||
if (!hdhomerun_device_get_device_addr(hd, &device_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (hd->cs) {
|
||||
return hdhomerun_control_get_device_ip(hd->cs);
|
||||
if (device_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
struct sockaddr_in *device_addr_in = (struct sockaddr_in *)&device_addr;
|
||||
return ntohl(device_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_device_get_device_addr(struct hdhomerun_device_t *hd, struct sockaddr_storage *result)
|
||||
{
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
*result = hd->multicast_addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hd->cs) {
|
||||
memset(result, 0, sizeof(struct sockaddr_storage));
|
||||
return false;
|
||||
}
|
||||
|
||||
return hdhomerun_control_get_device_addr(hd->cs, result);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (hd->cs) {
|
||||
return hdhomerun_control_get_device_id_requested(hd->cs);
|
||||
}
|
||||
|
||||
if (!hd->cs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hdhomerun_control_get_device_id_requested(hd->cs);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
return hd->multicast_ip;
|
||||
struct sockaddr_storage device_addr;
|
||||
if (!hdhomerun_device_get_device_addr_requested(hd, &device_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (hd->cs) {
|
||||
return hdhomerun_control_get_device_ip_requested(hd->cs);
|
||||
if (device_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
struct sockaddr_in *device_addr_in = (struct sockaddr_in *)&device_addr;
|
||||
return ntohl(device_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_device_get_device_addr_requested(struct hdhomerun_device_t *hd, struct sockaddr_storage *result)
|
||||
{
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
*result = hd->multicast_addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hd->cs) {
|
||||
memset(result, 0, sizeof(struct sockaddr_storage));
|
||||
return false;
|
||||
}
|
||||
|
||||
return hdhomerun_control_get_device_addr_requested(hd->cs, result);
|
||||
}
|
||||
|
||||
unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd)
|
||||
|
@ -339,9 +523,24 @@ struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_
|
|||
return hd->vs;
|
||||
}
|
||||
|
||||
bool allow_port_reuse = (hd->multicast_port != 0);
|
||||
bool allow_port_reuse = false;
|
||||
struct sockaddr_storage listen_addr;
|
||||
memset(&listen_addr, 0, sizeof(listen_addr));
|
||||
|
||||
hd->vs = hdhomerun_video_create(hd->multicast_port, allow_port_reuse, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg);
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
listen_addr.ss_family = hd->multicast_addr.ss_family;
|
||||
hdhomerun_sock_sockaddr_set_port((struct sockaddr *)&listen_addr, hdhomerun_sock_sockaddr_get_port((struct sockaddr *)&hd->multicast_addr));
|
||||
allow_port_reuse = true;
|
||||
}
|
||||
|
||||
struct sockaddr_storage device_addr;
|
||||
if (!hdhomerun_control_get_device_addr(hd->cs, &device_addr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
listen_addr.ss_family = device_addr.ss_family;
|
||||
|
||||
hd->vs = hdhomerun_video_create_ex((struct sockaddr *)&listen_addr, allow_port_reuse, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg);
|
||||
if (!hd->vs) {
|
||||
hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_video_sock: failed to create video object\n");
|
||||
return NULL;
|
||||
|
@ -352,11 +551,26 @@ struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_
|
|||
|
||||
uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd)
|
||||
{
|
||||
if (hd->cs) {
|
||||
return hdhomerun_control_get_local_addr(hd->cs);
|
||||
struct sockaddr_storage local_addr;
|
||||
if (!hdhomerun_device_get_local_machine_addr_ex(hd, &local_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (local_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
struct sockaddr_in *local_addr_in = (struct sockaddr_in *)&local_addr;
|
||||
return ntohl(local_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_device_get_local_machine_addr_ex(struct hdhomerun_device_t *hd, struct sockaddr_storage *result)
|
||||
{
|
||||
if (!hd->cs) {
|
||||
memset(result, 0, sizeof(struct sockaddr_storage));
|
||||
return false;
|
||||
}
|
||||
|
||||
return hdhomerun_control_get_local_addr_ex(hd->cs, result);
|
||||
}
|
||||
|
||||
static uint32_t hdhomerun_device_get_status_parse(const char *status_str, const char *tag)
|
||||
|
@ -367,7 +581,7 @@ static uint32_t hdhomerun_device_get_status_parse(const char *status_str, const
|
|||
}
|
||||
|
||||
unsigned int value = 0;
|
||||
sscanf(ptr + strlen(tag), "%u", &value);
|
||||
(void)sscanf(ptr + strlen(tag), "%u", &value);
|
||||
|
||||
return (uint32_t)value;
|
||||
}
|
||||
|
@ -466,12 +680,12 @@ int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **psta
|
|||
if (status) {
|
||||
char *channel = strstr(status_str, "ch=");
|
||||
if (channel) {
|
||||
sscanf(channel + 3, "%31s", status->channel);
|
||||
(void)sscanf(channel + 3, "%31s", status->channel);
|
||||
}
|
||||
|
||||
char *lock = strstr(status_str, "lock=");
|
||||
if (lock) {
|
||||
sscanf(lock + 5, "%31s", status->lock_str);
|
||||
(void)sscanf(lock + 5, "%31s", status->lock_str);
|
||||
}
|
||||
|
||||
status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss=");
|
||||
|
@ -516,12 +730,12 @@ int hdhomerun_device_get_oob_status(struct hdhomerun_device_t *hd, char **pstatu
|
|||
if (status) {
|
||||
char *channel = strstr(status_str, "ch=");
|
||||
if (channel) {
|
||||
sscanf(channel + 3, "%31s", status->channel);
|
||||
(void)sscanf(channel + 3, "%31s", status->channel);
|
||||
}
|
||||
|
||||
char *lock = strstr(status_str, "lock=");
|
||||
if (lock) {
|
||||
sscanf(lock + 5, "%31s", status->lock_str);
|
||||
(void)sscanf(lock + 5, "%31s", status->lock_str);
|
||||
}
|
||||
|
||||
status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss=");
|
||||
|
@ -558,27 +772,27 @@ int hdhomerun_device_get_tuner_vstatus(struct hdhomerun_device_t *hd, char **pvs
|
|||
if (vstatus) {
|
||||
char *vch = strstr(vstatus_str, "vch=");
|
||||
if (vch) {
|
||||
sscanf(vch + 4, "%31s", vstatus->vchannel);
|
||||
(void)sscanf(vch + 4, "%31s", vstatus->vchannel);
|
||||
}
|
||||
|
||||
char *name = strstr(vstatus_str, "name=");
|
||||
if (name) {
|
||||
sscanf(name + 5, "%31s", vstatus->name);
|
||||
(void)sscanf(name + 5, "%31s", vstatus->name);
|
||||
}
|
||||
|
||||
char *auth = strstr(vstatus_str, "auth=");
|
||||
if (auth) {
|
||||
sscanf(auth + 5, "%31s", vstatus->auth);
|
||||
(void)sscanf(auth + 5, "%31s", vstatus->auth);
|
||||
}
|
||||
|
||||
char *cci = strstr(vstatus_str, "cci=");
|
||||
if (cci) {
|
||||
sscanf(cci + 4, "%31s", vstatus->cci);
|
||||
(void)sscanf(cci + 4, "%31s", vstatus->cci);
|
||||
}
|
||||
|
||||
char *cgms = strstr(vstatus_str, "cgms=");
|
||||
if (cgms) {
|
||||
sscanf(cgms + 5, "%31s", vstatus->cgms);
|
||||
(void)sscanf(cgms + 5, "%31s", vstatus->cgms);
|
||||
}
|
||||
|
||||
if (strncmp(vstatus->auth, "not-subscribed", 14) == 0) {
|
||||
|
@ -1049,7 +1263,7 @@ int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, co
|
|||
|
||||
int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
return 1;
|
||||
}
|
||||
if (!hd->cs) {
|
||||
|
@ -1077,7 +1291,7 @@ int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char *
|
|||
|
||||
int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
return 1;
|
||||
}
|
||||
if (!hd->cs) {
|
||||
|
@ -1099,7 +1313,7 @@ int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd)
|
|||
|
||||
int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
return 1;
|
||||
}
|
||||
if (!hd->cs) {
|
||||
|
@ -1117,7 +1331,7 @@ int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd)
|
|||
|
||||
void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey)
|
||||
{
|
||||
if (hd->multicast_ip != 0) {
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1163,8 +1377,10 @@ int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
|
|||
hdhomerun_video_set_keepalive(hd->vs, 0, 0, 0);
|
||||
|
||||
/* Set target. */
|
||||
if (hd->multicast_ip != 0) {
|
||||
int ret = hdhomerun_video_join_multicast_group(hd->vs, hd->multicast_ip, 0);
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
struct sockaddr local_ip;
|
||||
memset(&local_ip, 0, sizeof(local_ip));
|
||||
int ret = hdhomerun_video_join_multicast_group_ex(hd->vs, (struct sockaddr *)&hd->multicast_addr, &local_ip);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1216,8 +1432,10 @@ void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd)
|
|||
return;
|
||||
}
|
||||
|
||||
if (hd->multicast_ip != 0) {
|
||||
hdhomerun_video_leave_multicast_group(hd->vs, hd->multicast_ip, 0);
|
||||
if (hdhomerun_sock_sockaddr_is_addr((struct sockaddr *)&hd->multicast_addr)) {
|
||||
struct sockaddr local_ip;
|
||||
memset(&local_ip, 0, sizeof(local_ip));
|
||||
hdhomerun_video_leave_multicast_group_ex(hd->vs, (struct sockaddr *)&hd->multicast_addr, &local_ip);
|
||||
} else {
|
||||
hdhomerun_device_set_tuner_target(hd, "none");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_device.h
|
||||
*
|
||||
* Copyright © 2006-2015 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -64,7 +64,9 @@ extern "C" {
|
|||
* /tuner<tuner index>
|
||||
*/
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create_ex(uint32_t device_id, const struct sockaddr *device_addr, unsigned int tuner, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create_multicast(uint32_t multicast_ip, uint16_t multicast_port, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create_multicast_ex(const struct sockaddr *multicast_addr, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_device_destroy(struct hdhomerun_device_t *hd);
|
||||
|
||||
|
@ -74,12 +76,16 @@ extern LIBHDHOMERUN_API void hdhomerun_device_destroy(struct hdhomerun_device_t
|
|||
extern LIBHDHOMERUN_API const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_device_get_device_addr(struct hdhomerun_device_t *hd, struct sockaddr_storage *result);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_device_get_device_addr_requested(struct hdhomerun_device_t *hd, struct sockaddr_storage *result);
|
||||
extern LIBHDHOMERUN_API unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd);
|
||||
|
||||
extern LIBHDHOMERUN_API int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_device_set_device_ex(struct hdhomerun_device_t *hd, uint32_t device_id, const struct sockaddr *device_addr);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_device_set_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip, uint16_t multicast_port);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_device_set_multicast_ex(struct hdhomerun_device_t *hd, const struct sockaddr *multicast_addr);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str);
|
||||
|
||||
|
@ -91,6 +97,7 @@ extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_from_str(struct hdhomerun
|
|||
* Returns 32-bit IP address with native endianness, or 0 on error.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_device_get_local_machine_addr_ex(struct hdhomerun_device_t *hd, struct sockaddr_storage *result);
|
||||
|
||||
/*
|
||||
* Get operations.
|
||||
|
|
1874
hdhomerun_discover.c
1874
hdhomerun_discover.c
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_discover.h
|
||||
*
|
||||
* Copyright © 2006-2019 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -21,6 +21,111 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL (1 << 0)
|
||||
#define HDHOMERUN_DISCOVER_FLAGS_IPV4_LOCALHOST (1 << 1)
|
||||
#define HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL (1 << 2)
|
||||
#define HDHOMERUN_DISCOVER_FLAGS_IPV6_LINKLOCAL (1 << 3)
|
||||
#define HDHOMERUN_DISCOVER_FLAGS_IPV6_LOCALHOST (1 << 4)
|
||||
|
||||
struct hdhomerun_discover2_device_t;
|
||||
struct hdhomerun_discover2_device_if_t;
|
||||
|
||||
/*
|
||||
* Discover object.
|
||||
*
|
||||
* May be maintained and reused across the lifespan of the app or may be created and destroyed for each discover.
|
||||
* If the app polls discover the same discover instance should be reused to avoid burning through local IP ports.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_discover_t *hdhomerun_discover_create(struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds);
|
||||
|
||||
/*
|
||||
* Discover API:
|
||||
*
|
||||
* Use hdhomerun_discover2_find_devices_broadcast() to find all devices on the local subnet.
|
||||
* flags: IPv4 only use HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL
|
||||
* flags: IPv4 and IPv6 use HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL | HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL
|
||||
* flags: Linklocal IPv6 requires special handling (scope id) - only include HDHOMERUN_DISCOVER_FLAGS_IPV6_LINKLOCAL if the app tracks scope id needed for linklocal IPv6.
|
||||
* device_types: do not use HDHOMERUN_DEVICE_TYPE_WILDCARD, instead provide an array of types the app wants to discover, for example:
|
||||
* uint32_t device_types[2];
|
||||
* device_types[0] = HDHOMERUN_DEVICE_TYPE_TUNER;
|
||||
* device_types[1] = HDHOMERUN_DEVICE_TYPE_STORAGE;
|
||||
* Returns 1 when one or more devices are found.
|
||||
* 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_device_id_broadcast(struct hdhomerun_discover_t *ds, uint32_t flags, uint32_t device_id);
|
||||
|
||||
/*
|
||||
* Discover result access API.
|
||||
*
|
||||
* Use hdhomerun_discover2_iter_device_first() and hdhomerun_discover2_iter_device_next() to iterate through discover results.
|
||||
* Use hdhomerun_discover2_device_xxx() APIs to query properties of the device.
|
||||
*
|
||||
* Use hdhomerun_discover2_iter_device_if_first() to select the first (best) set of device URLs.
|
||||
* Use hdhomerun_discover2_device_if_xxx() to query specific device URLs.
|
||||
*
|
||||
* In most cases hdhomerun_discover2_iter_device_if_next() will not be used as the app should use the first set of URLs.
|
||||
*
|
||||
* Results are available until a new discover is run on the same discover object or until the discover object is destroyed. Strings shoud be copied.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_discover2_device_t *hdhomerun_discover2_iter_device_first(struct hdhomerun_discover_t *ds);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_discover2_device_t *hdhomerun_discover2_iter_device_next(struct hdhomerun_discover2_device_t *device);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_discover2_device_if_t *hdhomerun_discover2_iter_device_if_first(struct hdhomerun_discover2_device_t *device);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_discover2_device_if_t *hdhomerun_discover2_iter_device_if_next(struct hdhomerun_discover2_device_if_t *device_if);
|
||||
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover2_device_is_legacy(struct hdhomerun_discover2_device_t *device);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover2_device_is_type(struct hdhomerun_discover2_device_t *device, uint32_t device_type);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_discover2_device_get_device_id(struct hdhomerun_discover2_device_t *device);
|
||||
extern LIBHDHOMERUN_API const char *hdhomerun_discover2_device_get_storage_id(struct hdhomerun_discover2_device_t *device);
|
||||
extern LIBHDHOMERUN_API uint8_t hdhomerun_discover2_device_get_tuner_count(struct hdhomerun_discover2_device_t *device);
|
||||
extern LIBHDHOMERUN_API const char *hdhomerun_discover2_device_get_device_auth(struct hdhomerun_discover2_device_t *device);
|
||||
|
||||
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 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);
|
||||
extern LIBHDHOMERUN_API const char *hdhomerun_discover2_device_if_get_storage_url(struct hdhomerun_discover2_device_if_t *device_if);
|
||||
|
||||
/*
|
||||
* Verify that the device ID given is valid.
|
||||
*
|
||||
* The device ID contains a self-check sequence that detects common user input errors including
|
||||
* single-digit errors and two digit transposition errors.
|
||||
*
|
||||
* Returns true if valid.
|
||||
* Returns false if not valid.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover_validate_device_id(uint32_t device_id);
|
||||
|
||||
/*
|
||||
* Detect if an IP address is multicast.
|
||||
*
|
||||
* Returns true if multicast.
|
||||
* Returns false if zero, unicast, expermental, or broadcast.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover_is_ip_multicast(uint32_t ip_addr);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover_is_ip_multicast_ex(const struct sockaddr *ip_addr);
|
||||
|
||||
/*
|
||||
* Legacy API - not for new applications.
|
||||
*
|
||||
* The device information is stored in caller-supplied array of hdhomerun_discover_device_t vars.
|
||||
* Multiple attempts are made to find devices.
|
||||
* Execution time is typically 400ms unless max_count is reached.
|
||||
*
|
||||
* Set target_ip to zero to auto-detect the IP address.
|
||||
* Set device_type to HDHOMERUN_DEVICE_TYPE_TUNER to detect HDHomeRun tuner devices.
|
||||
* Set device_id to HDHOMERUN_DEVICE_ID_WILDCARD to detect all device ids.
|
||||
*
|
||||
* Returns the number of devices found.
|
||||
* Retruns -1 on error.
|
||||
*/
|
||||
|
||||
struct hdhomerun_discover_device_t {
|
||||
uint32_t ip_addr;
|
||||
uint32_t device_type;
|
||||
|
@ -45,50 +150,12 @@ struct hdhomerun_discover_device_v3_t {
|
|||
char storage_url[128];
|
||||
};
|
||||
|
||||
/*
|
||||
* Find devices.
|
||||
*
|
||||
* The device information is stored in caller-supplied array of hdhomerun_discover_device_t vars.
|
||||
* Multiple attempts are made to find devices.
|
||||
* Execution time is typically 400ms unless max_count is reached.
|
||||
*
|
||||
* Set target_ip to zero to auto-detect the IP address.
|
||||
* Set device_type to HDHOMERUN_DEVICE_TYPE_TUNER to detect HDHomeRun tuner devices.
|
||||
* Set device_id to HDHOMERUN_DEVICE_ID_WILDCARD to detect all device ids.
|
||||
*
|
||||
* Returns the number of devices found.
|
||||
* Retruns -1 on error.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover_find_devices_custom_v2(uint32_t target_ip, uint32_t device_type_match, uint32_t device_id_match, struct hdhomerun_discover_device_t result_list[], int max_count);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover_find_devices_custom_v3(uint32_t target_ip, uint32_t device_type_match, uint32_t device_id_match, struct hdhomerun_discover_device_v3_t result_list[], int max_count);
|
||||
|
||||
/*
|
||||
* Optional: persistent discover instance available for discover polling use.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_discover_t *hdhomerun_discover_create(struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover_find_devices_v2(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type_match, uint32_t device_id_match, struct hdhomerun_discover_device_t result_list[], int max_count);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_discover_find_devices_v3(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type_match, uint32_t device_id_match, struct hdhomerun_discover_device_v3_t result_list[], int max_count);
|
||||
|
||||
/*
|
||||
* Verify that the device ID given is valid.
|
||||
*
|
||||
* The device ID contains a self-check sequence that detects common user input errors including
|
||||
* single-digit errors and two digit transposition errors.
|
||||
*
|
||||
* Returns true if valid.
|
||||
* Returns false if not valid.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover_validate_device_id(uint32_t device_id);
|
||||
|
||||
/*
|
||||
* Detect if an IP address is multicast.
|
||||
*
|
||||
* Returns true if multicast.
|
||||
* Returns false if zero, unicast, expermental, or broadcast.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_discover_is_ip_multicast(uint32_t ip_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_pkt.h
|
||||
*
|
||||
* Copyright © 2006-2015 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -133,6 +133,7 @@ extern "C" {
|
|||
#define HDHOMERUN_TAG_BASE_URL 0x2A
|
||||
#define HDHOMERUN_TAG_DEVICE_AUTH_STR 0x2B
|
||||
#define HDHOMERUN_TAG_STORAGE_ID 0x2C
|
||||
#define HDHOMERUN_TAG_MULTI_TYPE 0x2D
|
||||
|
||||
#define HDHOMERUN_DEVICE_TYPE_WILDCARD 0xFFFFFFFF
|
||||
#define HDHOMERUN_DEVICE_TYPE_TUNER 0x00000001
|
||||
|
|
380
hdhomerun_sock.c
Normal file
380
hdhomerun_sock.c
Normal file
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* hdhomerun_sock.c
|
||||
*
|
||||
* Copyright © 2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hdhomerun.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <netioapi.h>
|
||||
#else
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WINRT)
|
||||
static inline uint32_t if_nametoindex(const char *ifname) { return 0; }
|
||||
#endif
|
||||
|
||||
bool hdhomerun_sock_sockaddr_is_addr(const struct sockaddr *addr)
|
||||
{
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
static uint8_t hdhomerun_sock_ipv6_zero_bytes[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)addr;
|
||||
return (memcmp(addr_in6->sin6_addr.s6_addr, hdhomerun_sock_ipv6_zero_bytes, 16) != 0);
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
const struct sockaddr_in *addr_in = (const struct sockaddr_in *)addr;
|
||||
return (addr_in->sin_addr.s_addr != 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t hdhomerun_sock_sockaddr_get_port(const struct sockaddr *addr)
|
||||
{
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)addr;
|
||||
return ntohs(addr_in6->sin6_port);
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
const struct sockaddr_in *addr_in = (const struct sockaddr_in *)addr;
|
||||
return ntohs(addr_in->sin_port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hdhomerun_sock_sockaddr_set_port(struct sockaddr *addr, uint16_t port)
|
||||
{
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
|
||||
addr_in6->sin6_port = htons(port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
|
||||
addr_in->sin_port = htons(port);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void hdhomerun_sock_sockaddr_copy(struct sockaddr_storage *result, const struct sockaddr *addr)
|
||||
{
|
||||
memset(result, 0, sizeof(struct sockaddr_storage));
|
||||
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
memcpy(result, addr, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
memcpy(result, addr, sizeof(struct sockaddr_in));
|
||||
}
|
||||
}
|
||||
|
||||
void hdhomerun_sock_sockaddr_to_ip_str(char ip_str[64], const struct sockaddr *ip_addr, bool include_ipv6_scope_id)
|
||||
{
|
||||
size_t ip_str_size = 64;
|
||||
|
||||
if (ip_addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *ip_addr_in6 = (const struct sockaddr_in6 *)ip_addr;
|
||||
inet_ntop(AF_INET6, ip_addr_in6->sin6_addr.s6_addr, ip_str, ip_str_size);
|
||||
if (include_ipv6_scope_id && (ip_addr_in6->sin6_scope_id != 0)) {
|
||||
hdhomerun_sprintf(strchr(ip_str, 0), ip_str + ip_str_size, "%%%u", ip_addr_in6->sin6_scope_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ip_addr->sa_family == AF_INET) {
|
||||
const struct sockaddr_in *ip_addr_in = (const struct sockaddr_in *)ip_addr;
|
||||
inet_ntop(AF_INET, &ip_addr_in->sin_addr.s_addr, ip_str, ip_str_size);
|
||||
return;
|
||||
}
|
||||
|
||||
ip_str[0] = 0;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_ip_str_to_sockaddr(const char *ip_str, struct sockaddr_storage *result)
|
||||
{
|
||||
memset(result, 0, sizeof(struct sockaddr_storage));
|
||||
|
||||
struct sockaddr_in *result_in = (struct sockaddr_in *)result;
|
||||
if (inet_pton(AF_INET, ip_str, &result_in->sin_addr) == 1) {
|
||||
result_in->sin_family = AF_INET;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool framed = (*ip_str == '[');
|
||||
bool ifname_present = (strchr(ip_str, '%') != NULL);
|
||||
|
||||
if (!framed && !ifname_present) {
|
||||
struct sockaddr_in6 *result_in6 = (struct sockaddr_in6 *)result;
|
||||
if (inet_pton(AF_INET6, ip_str, &result_in6->sin6_addr) == 1) {
|
||||
result_in6->sin6_family = AF_INET6;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (framed) {
|
||||
ip_str++;
|
||||
}
|
||||
|
||||
char ip_str_tmp[64];
|
||||
if (!hdhomerun_sprintf(ip_str_tmp, ip_str_tmp + sizeof(ip_str_tmp), "%s", ip_str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (framed) {
|
||||
char *end = strchr(ip_str_tmp, ']');
|
||||
if (!end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*end++ = 0;
|
||||
if (*end) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char *ifname = NULL;
|
||||
if (ifname_present) {
|
||||
ifname = strchr(ip_str_tmp, '%');
|
||||
*ifname++ = 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in6 *result_in6 = (struct sockaddr_in6 *)result;
|
||||
if (inet_pton(AF_INET6, ip_str_tmp, &result_in6->sin6_addr) != 1) {
|
||||
return false;
|
||||
}
|
||||
result_in6->sin6_family = AF_INET6;
|
||||
|
||||
if (!ifname_present) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char *end;
|
||||
result_in6->sin6_scope_id = (uint32_t)strtoul(ifname, &end, 10);
|
||||
if ((result_in6->sin6_scope_id > 0) && (*end == 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
result_in6->sin6_scope_id = if_nametoindex(ifname);
|
||||
return (result_in6->sin6_scope_id > 0);
|
||||
}
|
||||
|
||||
struct hdhomerun_local_ip_info_state_t {
|
||||
struct hdhomerun_local_ip_info_t *ip_info;
|
||||
int max_count;
|
||||
int count;
|
||||
};
|
||||
|
||||
static void hdhomerun_local_ip_info_callback(void *arg, uint32_t ifindex, const struct sockaddr *local_ip, uint8_t cidr)
|
||||
{
|
||||
struct hdhomerun_local_ip_info_state_t *state = (struct hdhomerun_local_ip_info_state_t *)arg;
|
||||
|
||||
if (state->count >= state->max_count) {
|
||||
state->count++;
|
||||
return;
|
||||
}
|
||||
|
||||
const struct sockaddr_in *local_ip_in = (const struct sockaddr_in *)local_ip;
|
||||
state->ip_info->ip_addr = ntohl(local_ip_in->sin_addr.s_addr);
|
||||
state->ip_info->subnet_mask = 0xFFFFFFFF << (32 - cidr);
|
||||
state->ip_info++;
|
||||
state->count++;
|
||||
}
|
||||
|
||||
int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count)
|
||||
{
|
||||
struct hdhomerun_local_ip_info_state_t state;
|
||||
state.ip_info = ip_info_list;
|
||||
state.max_count = max_count;
|
||||
state.count = 0;
|
||||
|
||||
if (!hdhomerun_local_ip_info2(AF_INET, hdhomerun_local_ip_info_callback, &state)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return state.count;
|
||||
}
|
||||
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void)
|
||||
{
|
||||
return hdhomerun_sock_create_udp_ex(AF_INET);
|
||||
}
|
||||
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_tcp(void)
|
||||
{
|
||||
return hdhomerun_sock_create_tcp_ex(AF_INET);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getsockname_addr(struct hdhomerun_sock_t *sock)
|
||||
{
|
||||
struct sockaddr_storage sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
|
||||
if (!hdhomerun_sock_getsockname_addr_ex(sock, &sock_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (sock_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&sock_addr;
|
||||
return ntohl(sock_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getpeername_addr(struct hdhomerun_sock_t *sock)
|
||||
{
|
||||
struct sockaddr_storage sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
|
||||
if (!hdhomerun_sock_getpeername_addr_ex(sock, &sock_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (sock_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&sock_addr;
|
||||
return ntohl(sock_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getaddrinfo_addr(struct hdhomerun_sock_t *sock, const char *name)
|
||||
{
|
||||
struct sockaddr_storage sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
|
||||
if (!hdhomerun_sock_getaddrinfo_addr_ex(AF_INET, name, &sock_addr)) {
|
||||
return 0;
|
||||
}
|
||||
if (sock_addr.ss_family != AF_INET) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&sock_addr;
|
||||
return ntohl(sock_addr_in->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_getaddrinfo_addr_ex(int af, const char *name, struct sockaddr_storage *result)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = af;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
struct addrinfo *sock_info;
|
||||
if (getaddrinfo(name, NULL, &hints, &sock_info) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((size_t)sock_info->ai_addrlen > sizeof(struct sockaddr_storage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(result, sock_info->ai_addr, sock_info->ai_addrlen);
|
||||
freeaddrinfo(sock_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip)
|
||||
{
|
||||
struct sockaddr_in multicast_addr;
|
||||
memset(&multicast_addr, 0, sizeof(multicast_addr));
|
||||
multicast_addr.sin_family = AF_INET;
|
||||
multicast_addr.sin_addr.s_addr = htonl(multicast_ip);
|
||||
|
||||
struct sockaddr_in local_addr;
|
||||
memset(&local_addr, 0, sizeof(local_addr));
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_addr.s_addr = htonl(local_ip);
|
||||
|
||||
return hdhomerun_sock_join_multicast_group_ex(sock, (const struct sockaddr *)&multicast_addr, (const struct sockaddr *)&local_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip)
|
||||
{
|
||||
struct sockaddr_in multicast_addr;
|
||||
memset(&multicast_addr, 0, sizeof(multicast_addr));
|
||||
multicast_addr.sin_family = AF_INET;
|
||||
multicast_addr.sin_addr.s_addr = htonl(multicast_ip);
|
||||
|
||||
struct sockaddr_in local_addr;
|
||||
memset(&local_addr, 0, sizeof(local_addr));
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_addr.s_addr = htonl(local_ip);
|
||||
|
||||
return hdhomerun_sock_leave_multicast_group_ex(sock, (const struct sockaddr *)&multicast_addr, (const struct sockaddr *)&local_addr);
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_bind(struct hdhomerun_sock_t *sock, uint32_t local_addr, uint16_t local_port, bool allow_reuse)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(local_addr);
|
||||
sock_addr.sin_port = htons(local_port);
|
||||
|
||||
return hdhomerun_sock_bind_ex(sock, (const struct sockaddr *)&sock_addr, allow_reuse);
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_connect(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout)
|
||||
{
|
||||
struct sockaddr_in sock_addr_in;
|
||||
memset(&sock_addr_in, 0, sizeof(sock_addr_in));
|
||||
|
||||
sock_addr_in.sin_family = AF_INET;
|
||||
sock_addr_in.sin_addr.s_addr = htonl(remote_addr);
|
||||
sock_addr_in.sin_port = htons(remote_port);
|
||||
|
||||
return hdhomerun_sock_connect_ex(sock, (const struct sockaddr *)&sock_addr_in, timeout);
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout)
|
||||
{
|
||||
struct sockaddr_in sock_addr_in;
|
||||
memset(&sock_addr_in, 0, sizeof(sock_addr_in));
|
||||
|
||||
sock_addr_in.sin_family = AF_INET;
|
||||
sock_addr_in.sin_addr.s_addr = htonl(remote_addr);
|
||||
sock_addr_in.sin_port = htons(remote_port);
|
||||
|
||||
return hdhomerun_sock_sendto_ex(sock, (const struct sockaddr *)&sock_addr_in, data, length, timeout);
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout)
|
||||
{
|
||||
struct sockaddr_storage sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
|
||||
if (!hdhomerun_sock_recvfrom_ex(sock, &sock_addr, data, length, timeout)) {
|
||||
return false;
|
||||
}
|
||||
if (sock_addr.ss_family != AF_INET) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&sock_addr;
|
||||
*remote_addr = ntohl(sock_addr_in->sin_addr.s_addr);
|
||||
*remote_port = ntohs(sock_addr_in->sin_port);
|
||||
return true;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_sock.h
|
||||
*
|
||||
* Copyright © 2010-2016 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2010-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -21,42 +21,81 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Windows:
|
||||
* hdhomerun_sock.c
|
||||
* hdhomerun_sock_windows.c
|
||||
*
|
||||
* Linux/Android:
|
||||
* hdhomerun_sock.c
|
||||
* hdhomerun_sock_netlink.c
|
||||
* hdhomerun_sock_posix.c
|
||||
*
|
||||
* Mac/BSD:
|
||||
* hdhomerun_sock.c
|
||||
* hdhomerun_sock_getifaddrs.c
|
||||
* hdhomerun_sock_posix.c
|
||||
*/
|
||||
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_sockaddr_is_addr(const struct sockaddr *addr);
|
||||
extern LIBHDHOMERUN_API uint16_t hdhomerun_sock_sockaddr_get_port(const struct sockaddr *addr);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_sockaddr_set_port(struct sockaddr *addr, uint16_t port);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_sockaddr_copy(struct sockaddr_storage *result, const struct sockaddr *addr);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_sockaddr_to_ip_str(char ip_str[64], const struct sockaddr *ip_addr, bool include_ipv6_scope_id);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_ip_str_to_sockaddr(const char *ip_str, struct sockaddr_storage *result);
|
||||
|
||||
struct hdhomerun_local_ip_info_t {
|
||||
uint32_t ip_addr;
|
||||
uint32_t subnet_mask;
|
||||
};
|
||||
|
||||
typedef void (*hdhomerun_local_ip_info2_callback_t)(void *arg, uint32_t ifindex, const struct sockaddr *local_ip, uint8_t cidr);
|
||||
|
||||
extern LIBHDHOMERUN_API int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_local_ip_info_set_str(const char *ip_info_str); /* WinRT only */
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callback, void *callback_arg);
|
||||
|
||||
struct hdhomerun_sock_t;
|
||||
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_sock_t *hdhomerun_sock_create_tcp(void);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_sock_t *hdhomerun_sock_create_udp_ex(int af);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_sock_t *hdhomerun_sock_create_tcp_ex(int af);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_stop(struct hdhomerun_sock_t *sock);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_sock_destroy(struct hdhomerun_sock_t *sock);
|
||||
|
||||
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_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);
|
||||
|
||||
extern LIBHDHOMERUN_API int hdhomerun_sock_getlasterror(void);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_sock_getsockname_addr(struct hdhomerun_sock_t *sock);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_getsockname_addr_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *result);
|
||||
extern LIBHDHOMERUN_API uint16_t hdhomerun_sock_getsockname_port(struct hdhomerun_sock_t *sock);
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_sock_getpeername_addr(struct hdhomerun_sock_t *sock);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_getpeername_addr_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *result);
|
||||
|
||||
extern LIBHDHOMERUN_API uint32_t hdhomerun_sock_getaddrinfo_addr(struct hdhomerun_sock_t *sock, const char *name);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_getaddrinfo_addr_ex(int af, const char *name, struct sockaddr_storage *result);
|
||||
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_join_multicast_group_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_leave_multicast_group_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr);
|
||||
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_bind(struct hdhomerun_sock_t *sock, uint32_t local_addr, uint16_t local_port, bool allow_reuse);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_bind_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *local_addr, bool allow_reuse);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_connect(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_connect_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *remote_addr, uint64_t timeout);
|
||||
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_send(struct hdhomerun_sock_t *sock, const void *data, size_t length, uint64_t timeout);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_sendto_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *remote_addr, const void *data, size_t length, uint64_t timeout);
|
||||
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_recv(struct hdhomerun_sock_t *sock, void *data, size_t *length, uint64_t timeout);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout);
|
||||
extern LIBHDHOMERUN_API bool hdhomerun_sock_recvfrom_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *remote_addr, void *data, size_t *length, uint64_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
130
hdhomerun_sock_getifaddrs.c
Normal file
130
hdhomerun_sock_getifaddrs.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* hdhomerun_sock_getifaddrs.c
|
||||
*
|
||||
* Copyright © 2010-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hdhomerun.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
static uint8_t hdhomerun_local_ip_netmask_to_cidr(uint8_t *subnet_mask, size_t len)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
uint8_t *ptr = subnet_mask;
|
||||
uint8_t *end = subnet_mask + len;
|
||||
while (ptr < end) {
|
||||
uint8_t c = *ptr++;
|
||||
if (c == 0xFF) {
|
||||
result += 8;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (c & 0x80) {
|
||||
result++;
|
||||
c <<= 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callback, void *callback_arg)
|
||||
{
|
||||
int af6_sock = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (af6_sock == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ifaddrs *ifaddrs;
|
||||
if (getifaddrs(&ifaddrs) != 0) {
|
||||
close(af6_sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ifaddrs *ifa = ifaddrs;
|
||||
while (ifa) {
|
||||
if (ifa->ifa_addr == NULL) {
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((af != AF_UNSPEC) && (ifa->ifa_addr->sa_family != af)) {
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifa->ifa_addr->sa_family == AF_INET) {
|
||||
uint32_t ifindex = if_nametoindex(ifa->ifa_name);
|
||||
|
||||
struct sockaddr_in *netmask_in = (struct sockaddr_in *)ifa->ifa_netmask;
|
||||
uint8_t cidr = hdhomerun_local_ip_netmask_to_cidr((uint8_t *)&netmask_in->sin_addr.s_addr, 4);
|
||||
|
||||
callback(callback_arg, ifindex, ifa->ifa_addr, cidr);
|
||||
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6) {
|
||||
struct in6_ifreq ifr6;
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
|
||||
struct sockaddr_in6 *addr_in = (struct sockaddr_in6 *)ifa->ifa_addr;
|
||||
strcpy(ifr6.ifr_name, ifa->ifa_name);
|
||||
ifr6.ifr_addr = *addr_in;
|
||||
|
||||
if (ioctl(af6_sock, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime != 0xFFFFFFFF) {
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t ifindex = if_nametoindex(ifa->ifa_name);
|
||||
|
||||
struct sockaddr_in6 *netmask_in = (struct sockaddr_in6 *)ifa->ifa_netmask;
|
||||
uint8_t cidr = hdhomerun_local_ip_netmask_to_cidr(netmask_in->sin6_addr.s6_addr, 16);
|
||||
|
||||
callback(callback_arg, ifindex, ifa->ifa_addr, cidr);
|
||||
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
ifa = ifa->ifa_next;
|
||||
}
|
||||
|
||||
close(af6_sock);
|
||||
freeifaddrs(ifaddrs);
|
||||
return true;
|
||||
}
|
130
hdhomerun_sock_netdevice.c
Normal file
130
hdhomerun_sock_netdevice.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* hdhomerun_sock_getifaddrs.c
|
||||
*
|
||||
* Copyright © 2010-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hdhomerun.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
static uint8_t hdhomerun_local_ip_netmask_to_cidr(uint8_t *subnet_mask, size_t len)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
uint8_t *ptr = subnet_mask;
|
||||
uint8_t *end = subnet_mask + len;
|
||||
while (ptr < end) {
|
||||
uint8_t c = *ptr++;
|
||||
if (c == 0xFF) {
|
||||
result += 8;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (c & 0x80) {
|
||||
result++;
|
||||
c <<= 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callback, void *callback_arg)
|
||||
{
|
||||
if (af != AF_INET) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (sock == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ifreq_buffer_size = 128 * sizeof(struct ifreq);
|
||||
char *ifreq_buffer = (char *)calloc(ifreq_buffer_size, 1);
|
||||
if (!ifreq_buffer) {
|
||||
close(sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ifconf ifc;
|
||||
ifc.ifc_len = ifreq_buffer_size;
|
||||
ifc.ifc_buf = ifreq_buffer;
|
||||
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) {
|
||||
free(ifreq_buffer);
|
||||
close(sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ifc.ifc_len > ifreq_buffer_size) {
|
||||
ifc.ifc_len = ifreq_buffer_size;
|
||||
}
|
||||
|
||||
char *ptr = ifc.ifc_buf;
|
||||
char *end = ifc.ifc_buf + ifc.ifc_len;
|
||||
|
||||
while (ptr + sizeof(struct ifreq) <= end) {
|
||||
struct ifreq *ifr = (struct ifreq *)ptr;
|
||||
ptr += sizeof(struct ifreq);
|
||||
|
||||
/* 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) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Flags. */
|
||||
if (ioctl(sock, SIOCGIFFLAGS, ifr) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int flags = ifr->ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_UP | IFF_RUNNING | IFF_MULTICAST);
|
||||
if (flags != (IFF_UP | IFF_RUNNING | IFF_MULTICAST)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Subnet mask. */
|
||||
if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr_in *netmask_in = (struct sockaddr_in *)&ifr->ifr_addr;
|
||||
uint8_t cidr = hdhomerun_local_ip_netmask_to_cidr((uint8_t *)&netmask_in->sin_addr.s_addr, 4);
|
||||
|
||||
/* ifindex. */
|
||||
if (ioctl(sock, SIOCGIFINDEX, ifr) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t ifindex = ifr->ifr_ifindex;
|
||||
|
||||
/* Result. */
|
||||
callback(callback_arg, ifindex, (const struct sockaddr *)&ip_addr_in, cidr);
|
||||
}
|
||||
|
||||
free(ifreq_buffer);
|
||||
close(sock);
|
||||
return true;
|
||||
}
|
192
hdhomerun_sock_netlink.c
Normal file
192
hdhomerun_sock_netlink.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* hdhomerun_sock_netlink.c
|
||||
*
|
||||
* Copyright © 2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hdhomerun.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#define HDHOMERUN_SOCK_NETLINK_BUFFER_SIZE 32768
|
||||
|
||||
struct nlmsghdr_ifaddrmsg {
|
||||
struct nlmsghdr nlh;
|
||||
struct ifaddrmsg msg;
|
||||
};
|
||||
|
||||
static void hdhomerun_local_ip_info2_newaddr(int af_sock, struct nlmsghdr *hdr, hdhomerun_local_ip_info2_callback_t callback, void *callback_arg)
|
||||
{
|
||||
struct ifaddrmsg *addrmsg = (struct ifaddrmsg *)NLMSG_DATA(hdr);
|
||||
|
||||
if ((addrmsg->ifa_family != AF_INET) && (addrmsg->ifa_family != AF_INET6)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((addrmsg->ifa_family == AF_INET6) && (addrmsg->ifa_flags & IFA_F_TEMPORARY)) {
|
||||
return; /* skip temporary IPv6 addresses */
|
||||
}
|
||||
|
||||
/* ifindex */
|
||||
uint32_t ifindex = addrmsg->ifa_index;
|
||||
|
||||
/* interface flags */
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
if (!if_indextoname(ifindex, ifr.ifr_name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl(af_sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t flags = ifr.ifr_flags;
|
||||
flags &= (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_UP | IFF_RUNNING | IFF_MULTICAST);
|
||||
if (flags != (IFF_UP | IFF_RUNNING | IFF_MULTICAST)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* addresses */
|
||||
size_t ifa_payload_length = IFA_PAYLOAD(hdr);
|
||||
struct rtattr *rta = IFA_RTA(addrmsg);
|
||||
while (1) {
|
||||
if (!RTA_OK(rta, ifa_payload_length)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rta->rta_type != IFA_ADDRESS) {
|
||||
rta = RTA_NEXT(rta, ifa_payload_length);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t cidr = (uint8_t)addrmsg->ifa_prefixlen;
|
||||
|
||||
if (addrmsg->ifa_family == AF_INET) {
|
||||
struct sockaddr_in local_ip;
|
||||
memset(&local_ip, 0, sizeof(local_ip));
|
||||
|
||||
local_ip.sin_family = AF_INET;
|
||||
memcpy(&local_ip.sin_addr.s_addr, RTA_DATA(rta), 4);
|
||||
|
||||
callback(callback_arg, ifindex, (const struct sockaddr *)&local_ip, cidr);
|
||||
}
|
||||
|
||||
if (addrmsg->ifa_family == AF_INET6) {
|
||||
struct sockaddr_in6 local_ip;
|
||||
memset(&local_ip, 0, sizeof(local_ip));
|
||||
|
||||
local_ip.sin6_family = AF_INET6;
|
||||
memcpy(local_ip.sin6_addr.s6_addr, RTA_DATA(rta), 16);
|
||||
|
||||
if ((local_ip.sin6_addr.s6_addr[0] == 0xFE) && ((local_ip.sin6_addr.s6_addr[1] & 0xC0) == 0x80)) {
|
||||
local_ip.sin6_scope_id = ifindex;
|
||||
}
|
||||
|
||||
callback(callback_arg, ifindex, (const struct sockaddr *)&local_ip, cidr);
|
||||
}
|
||||
|
||||
rta = RTA_NEXT(rta, ifa_payload_length);
|
||||
}
|
||||
}
|
||||
|
||||
bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callback, void *callback_arg)
|
||||
{
|
||||
uint8_t *nl_buffer = (uint8_t *)malloc(HDHOMERUN_SOCK_NETLINK_BUFFER_SIZE);
|
||||
if (!nl_buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||
int af_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if ((nl_sock == -1) || (af_sock == -1)) {
|
||||
close(af_sock);
|
||||
close(nl_sock);
|
||||
free(nl_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct nlmsghdr_ifaddrmsg req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nlh.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req)));
|
||||
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||
req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
|
||||
req.msg.ifa_family = af;
|
||||
|
||||
if (send(nl_sock, &req, req.nlh.nlmsg_len, 0) != (ssize_t)req.nlh.nlmsg_len) {
|
||||
close(af_sock);
|
||||
close(nl_sock);
|
||||
free(nl_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool again = true;
|
||||
while (1) {
|
||||
struct pollfd poll_fds[1];
|
||||
poll_fds[0].fd = nl_sock;
|
||||
poll_fds[0].events = POLLIN;
|
||||
poll_fds[0].revents = 0;
|
||||
|
||||
int ret = poll(poll_fds, 1, 25);
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
}
|
||||
if ((poll_fds[0].revents & POLLIN) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int length = (int)recv(nl_sock, nl_buffer, HDHOMERUN_SOCK_NETLINK_BUFFER_SIZE, 0);
|
||||
if (length <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr *)nl_buffer;
|
||||
while (1) {
|
||||
if (!NLMSG_OK(hdr, length)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdr->nlmsg_type == NLMSG_DONE) {
|
||||
again = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdr->nlmsg_type == NLMSG_ERROR) {
|
||||
again = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdr->nlmsg_type == RTM_NEWADDR) {
|
||||
hdhomerun_local_ip_info2_newaddr(af_sock, hdr, callback, callback_arg);
|
||||
}
|
||||
|
||||
hdr = NLMSG_NEXT(hdr, length);
|
||||
}
|
||||
|
||||
if (!again) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(af_sock);
|
||||
close(nl_sock);
|
||||
free(nl_buffer);
|
||||
return true;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_sock_posix.c
|
||||
*
|
||||
* Copyright © 2010-2019 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2010-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -20,14 +20,6 @@
|
|||
|
||||
#include "hdhomerun.h"
|
||||
|
||||
#if defined(LIBHDHOMERUN_USE_SIOCGIFCONF)
|
||||
#include <sys/ioctl.h>
|
||||
#else
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#ifndef MSG_NOSIGNAL
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
@ -36,136 +28,7 @@ struct hdhomerun_sock_t {
|
|||
int sock;
|
||||
};
|
||||
|
||||
#if defined(LIBHDHOMERUN_USE_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, IPPROTO_IP);
|
||||
if (sock == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ifreq_buffer_size = 128 * sizeof(struct ifreq);
|
||||
char *ifreq_buffer = (char *)calloc(ifreq_buffer_size, 1);
|
||||
if (!ifreq_buffer) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ifconf ifc;
|
||||
ifc.ifc_len = ifreq_buffer_size;
|
||||
ifc.ifc_buf = ifreq_buffer;
|
||||
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) {
|
||||
free(ifreq_buffer);
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifc.ifc_len > ifreq_buffer_size) {
|
||||
ifc.ifc_len = ifreq_buffer_size;
|
||||
}
|
||||
|
||||
struct hdhomerun_local_ip_info_t *ip_info = ip_info_list;
|
||||
int count = 0;
|
||||
|
||||
char *ptr = ifc.ifc_buf;
|
||||
char *end = ifc.ifc_buf + ifc.ifc_len;
|
||||
|
||||
while (ptr + sizeof(struct ifreq) <= end) {
|
||||
struct ifreq *ifr = (struct ifreq *)ptr;
|
||||
ptr += sizeof(struct ifreq);
|
||||
|
||||
/* Local IP address. */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Flags. */
|
||||
if (ioctl(sock, SIOCGIFFLAGS, ifr) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int flags = ifr->ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_UP | IFF_RUNNING);
|
||||
if (flags != (IFF_UP | IFF_RUNNING)) {
|
||||
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);
|
||||
|
||||
/* Result. */
|
||||
if (count < max_count) {
|
||||
ip_info->ip_addr = ip_addr;
|
||||
ip_info->subnet_mask = subnet_mask;
|
||||
ip_info++;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ifaddrs *ifaddrs;
|
||||
if (getifaddrs(&ifaddrs) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct hdhomerun_local_ip_info_t *ip_info = ip_info_list;
|
||||
struct ifaddrs *ifa = ifaddrs;
|
||||
int count = 0;
|
||||
|
||||
while (ifa) {
|
||||
if (ifa->ifa_addr == NULL) {
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifa->ifa_addr->sa_family != AF_INET) {
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int flags = ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_UP | IFF_RUNNING);
|
||||
if (flags != (IFF_UP | IFF_RUNNING)) {
|
||||
ifa = ifa->ifa_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)ifa->ifa_addr;
|
||||
uint32_t ip_addr = ntohl(addr_in->sin_addr.s_addr);
|
||||
|
||||
struct sockaddr_in *netmask_in = (struct sockaddr_in *)ifa->ifa_netmask;
|
||||
uint32_t subnet_mask = ntohl(netmask_in->sin_addr.s_addr);
|
||||
|
||||
ifa = ifa->ifa_next;
|
||||
|
||||
if (count < max_count) {
|
||||
ip_info->ip_addr = ip_addr;
|
||||
ip_info->subnet_mask = subnet_mask;
|
||||
ip_info++;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddrs);
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol)
|
||||
static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int af, int protocol)
|
||||
{
|
||||
struct hdhomerun_sock_t *sock = (struct hdhomerun_sock_t *)calloc(1, sizeof(struct hdhomerun_sock_t));
|
||||
if (!sock) {
|
||||
|
@ -173,7 +36,7 @@ static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol)
|
|||
}
|
||||
|
||||
/* Create socket. */
|
||||
sock->sock = socket(AF_INET, protocol, 0);
|
||||
sock->sock = socket(af, protocol, 0);
|
||||
if (sock->sock == -1) {
|
||||
free(sock);
|
||||
return NULL;
|
||||
|
@ -191,13 +54,19 @@ static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol)
|
|||
setsockopt(sock->sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&set, sizeof(set));
|
||||
#endif
|
||||
|
||||
/* Set ipv6 */
|
||||
if (af == AF_INET6) {
|
||||
int sock_opt_ipv6only = 1;
|
||||
setsockopt(sock->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&sock_opt_ipv6only, sizeof(sock_opt_ipv6only));
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
return sock;
|
||||
}
|
||||
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void)
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_udp_ex(int af)
|
||||
{
|
||||
struct hdhomerun_sock_t *sock = hdhomerun_sock_create_internal(SOCK_DGRAM);
|
||||
struct hdhomerun_sock_t *sock = hdhomerun_sock_create_internal(af, SOCK_DGRAM);
|
||||
if (!sock) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -210,9 +79,9 @@ struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void)
|
|||
return sock;
|
||||
}
|
||||
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_tcp(void)
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_tcp_ex(int af)
|
||||
{
|
||||
return hdhomerun_sock_create_internal(SOCK_STREAM);
|
||||
return hdhomerun_sock_create_internal(af, SOCK_STREAM);
|
||||
}
|
||||
|
||||
void hdhomerun_sock_destroy(struct hdhomerun_sock_t *sock)
|
||||
|
@ -244,73 +113,80 @@ 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_ipv4_onesbcast(struct hdhomerun_sock_t *sock, int v)
|
||||
{
|
||||
#if defined(IP_ONESBCAST)
|
||||
setsockopt(sock->sock, IPPROTO_IP, IP_ONESBCAST, (char *)&v, sizeof(v));
|
||||
#endif
|
||||
}
|
||||
|
||||
void hdhomerun_sock_set_ipv6_multicast_ifindex(struct hdhomerun_sock_t *sock, uint32_t ifindex)
|
||||
{
|
||||
setsockopt(sock->sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&ifindex, sizeof(ifindex));
|
||||
}
|
||||
|
||||
int hdhomerun_sock_getlasterror(void)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getsockname_addr(struct hdhomerun_sock_t *sock)
|
||||
bool hdhomerun_sock_getsockname_addr_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *result)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
socklen_t sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ntohl(sock_addr.sin_addr.s_addr);
|
||||
socklen_t sockaddr_size = sizeof(struct sockaddr_storage);
|
||||
return (getsockname(sock->sock, (struct sockaddr *)result, &sockaddr_size) == 0);
|
||||
}
|
||||
|
||||
uint16_t hdhomerun_sock_getsockname_port(struct hdhomerun_sock_t *sock)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
struct sockaddr_storage sock_addr;
|
||||
socklen_t sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ntohs(sock_addr.sin_port);
|
||||
if (sock_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&sock_addr;
|
||||
return ntohs(sock_addr_in->sin_port);
|
||||
}
|
||||
if (sock_addr.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sock_addr_in = (struct sockaddr_in6 *)&sock_addr;
|
||||
return ntohs(sock_addr_in->sin6_port);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getpeername_addr(struct hdhomerun_sock_t *sock)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
socklen_t sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
if (getpeername(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ntohl(sock_addr.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getaddrinfo_addr(struct hdhomerun_sock_t *sock, const char *name)
|
||||
bool hdhomerun_sock_getpeername_addr_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *result)
|
||||
{
|
||||
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(name, NULL, &hints, &sock_info) != 0) {
|
||||
return 0;
|
||||
socklen_t sockaddr_size = sizeof(struct sockaddr_storage);
|
||||
return (getpeername(sock->sock, (struct sockaddr *)result, &sockaddr_size) == 0);
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr;
|
||||
uint32_t addr = ntohl(sock_addr->sin_addr.s_addr);
|
||||
|
||||
freeaddrinfo(sock_info);
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip)
|
||||
bool hdhomerun_sock_join_multicast_group_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr)
|
||||
{
|
||||
if (multicast_addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *multicast_addr_in = (const struct sockaddr_in6 *)multicast_addr;
|
||||
|
||||
struct ipv6_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
memcpy(imr.ipv6mr_multiaddr.s6_addr, multicast_addr_in->sin6_addr.s6_addr, 16);
|
||||
imr.ipv6mr_interface = multicast_addr_in->sin6_scope_id;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (multicast_addr->sa_family == AF_INET) {
|
||||
const struct sockaddr_in *multicast_addr_in = (const struct sockaddr_in *)multicast_addr;
|
||||
const struct sockaddr_in *local_addr_in = (const struct sockaddr_in *)local_addr;
|
||||
|
||||
struct ip_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
imr.imr_multiaddr.s_addr = htonl(multicast_ip);
|
||||
imr.imr_interface.s_addr = htonl(local_ip);
|
||||
imr.imr_multiaddr.s_addr = multicast_addr_in->sin_addr.s_addr;
|
||||
imr.imr_interface.s_addr = (local_addr->sa_family == AF_INET) ? local_addr_in->sin_addr.s_addr : 0;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
|
@ -319,12 +195,34 @@ bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_leave_multicast_group_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr)
|
||||
{
|
||||
if (multicast_addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *multicast_addr_in = (const struct sockaddr_in6 *)multicast_addr;
|
||||
|
||||
struct ipv6_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
memcpy(imr.ipv6mr_multiaddr.s6_addr, multicast_addr_in->sin6_addr.s6_addr, 16);
|
||||
imr.ipv6mr_interface = multicast_addr_in->sin6_scope_id;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (multicast_addr->sa_family == AF_INET) {
|
||||
const struct sockaddr_in *multicast_addr_in = (const struct sockaddr_in *)multicast_addr;
|
||||
const struct sockaddr_in *local_addr_in = (const struct sockaddr_in *)local_addr;
|
||||
|
||||
struct ip_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
imr.imr_multiaddr.s_addr = htonl(multicast_ip);
|
||||
imr.imr_interface.s_addr = htonl(local_ip);
|
||||
imr.imr_multiaddr.s_addr = multicast_addr_in->sin_addr.s_addr;
|
||||
imr.imr_interface.s_addr = (local_addr->sa_family == AF_INET) ? local_addr_in->sin_addr.s_addr : 0;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
|
@ -333,33 +231,48 @@ bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_
|
|||
return true;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_bind(struct hdhomerun_sock_t *sock, uint32_t local_addr, uint16_t local_port, bool allow_reuse)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_bind_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *local_addr, bool allow_reuse)
|
||||
{
|
||||
socklen_t local_addr_size;
|
||||
switch (local_addr->sa_family) {
|
||||
case AF_INET6:
|
||||
local_addr_size = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
case AF_INET:
|
||||
local_addr_size = (socklen_t)sizeof(struct sockaddr_in);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
int sock_opt = allow_reuse;
|
||||
setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt));
|
||||
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(local_addr);
|
||||
sock_addr.sin_port = htons(local_port);
|
||||
|
||||
if (bind(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
|
||||
if (bind(sock->sock, (const struct sockaddr *)local_addr, local_addr_size) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_connect(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout)
|
||||
bool hdhomerun_sock_connect_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *remote_addr, uint64_t timeout)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(remote_addr);
|
||||
sock_addr.sin_port = htons(remote_port);
|
||||
socklen_t remote_addr_size;
|
||||
switch (remote_addr->sa_family) {
|
||||
case AF_INET6:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
case AF_INET:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connect(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
|
||||
if (connect(sock->sock, remote_addr, remote_addr_size) != 0) {
|
||||
if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -437,16 +350,22 @@ bool hdhomerun_sock_send(struct hdhomerun_sock_t *sock, const void *data, size_t
|
|||
}
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout)
|
||||
bool hdhomerun_sock_sendto_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *remote_addr, const void *data, size_t length, uint64_t timeout)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(remote_addr);
|
||||
sock_addr.sin_port = htons(remote_port);
|
||||
socklen_t remote_addr_size;
|
||||
switch (remote_addr->sa_family) {
|
||||
case AF_INET6:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
case AF_INET:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t *ptr = (const uint8_t *)data;
|
||||
ssize_t ret = sendto(sock->sock, ptr, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
|
||||
ssize_t ret = sendto(sock->sock, ptr, length, 0, remote_addr, remote_addr_size);
|
||||
if (ret >= (ssize_t)length) {
|
||||
return true;
|
||||
}
|
||||
|
@ -476,7 +395,7 @@ bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr,
|
|||
return false;
|
||||
}
|
||||
|
||||
ret = sendto(sock->sock, ptr, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
|
||||
ret = sendto(sock->sock, ptr, length, 0, remote_addr, remote_addr_size);
|
||||
if (ret >= (ssize_t)length) {
|
||||
return true;
|
||||
}
|
||||
|
@ -536,16 +455,11 @@ bool hdhomerun_sock_recv(struct hdhomerun_sock_t *sock, void *data, size_t *leng
|
|||
return false;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout)
|
||||
bool hdhomerun_sock_recvfrom_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *remote_addr, void *data, size_t *length, uint64_t timeout)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
socklen_t sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
ssize_t ret = recvfrom(sock->sock, data, *length, 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
|
||||
socklen_t sockaddr_size = sizeof(struct sockaddr_storage);
|
||||
ssize_t ret = recvfrom(sock->sock, data, *length, 0, (struct sockaddr *)remote_addr, &sockaddr_size);
|
||||
if (ret > 0) {
|
||||
*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
|
||||
*remote_port = ntohs(sock_addr.sin_port);
|
||||
*length = (size_t)ret;
|
||||
return true;
|
||||
}
|
||||
|
@ -570,10 +484,8 @@ bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_add
|
|||
return false;
|
||||
}
|
||||
|
||||
ret = recvfrom(sock->sock, data, *length, 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
|
||||
ret = recvfrom(sock->sock, data, *length, 0, (struct sockaddr *)remote_addr, &sockaddr_size);
|
||||
if (ret > 0) {
|
||||
*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
|
||||
*remote_port = ntohs(sock_addr.sin_port);
|
||||
*length = (size_t)ret;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_sock_windows.c
|
||||
*
|
||||
* Copyright © 2010-2016 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2010-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -27,123 +27,78 @@ struct hdhomerun_sock_t {
|
|||
long events_selected;
|
||||
};
|
||||
|
||||
#if defined(_WINRT)
|
||||
static char *hdhomerun_local_ip_info_str = NULL;
|
||||
|
||||
/*
|
||||
* String format: ip address '/' subnet mask bits <space> ...
|
||||
* Example: "192.168.0.100/24 169.254.0.100/16"
|
||||
*/
|
||||
void hdhomerun_local_ip_info_set_str(const char *ip_info_str)
|
||||
bool hdhomerun_local_ip_info2(int af, hdhomerun_local_ip_info2_callback_t callback, void *callback_arg)
|
||||
{
|
||||
if (hdhomerun_local_ip_info_str) {
|
||||
free(hdhomerun_local_ip_info_str);
|
||||
}
|
||||
|
||||
hdhomerun_local_ip_info_str = strdup(ip_info_str);
|
||||
}
|
||||
|
||||
int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count)
|
||||
{
|
||||
const char *ptr = hdhomerun_local_ip_info_str;
|
||||
if (!ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hdhomerun_local_ip_info_t *ip_info = ip_info_list;
|
||||
int count = 0;
|
||||
|
||||
while (count < max_count) {
|
||||
unsigned int a[4];
|
||||
unsigned int mask_bitcount;
|
||||
if (sscanf(ptr, "%u.%u.%u.%u/%u", &a[0], &a[1], &a[2], &a[3], &mask_bitcount) != 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
ip_info->ip_addr = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
|
||||
ip_info->subnet_mask = 0xFFFFFFFF << (32 - mask_bitcount);
|
||||
ip_info++;
|
||||
|
||||
count++;
|
||||
|
||||
ptr = strchr(ptr, ' ');
|
||||
if (!ptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_WINRT)
|
||||
int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count)
|
||||
{
|
||||
PIP_ADAPTER_INFO AdapterInfo;
|
||||
ULONG AdapterInfoLength = sizeof(IP_ADAPTER_INFO) * 16;
|
||||
IP_ADAPTER_ADDRESSES *adapter_addresses;
|
||||
ULONG adapter_addresses_length = sizeof(IP_ADAPTER_ADDRESSES) * 16;
|
||||
|
||||
while (1) {
|
||||
AdapterInfo = (IP_ADAPTER_INFO *)malloc(AdapterInfoLength);
|
||||
if (!AdapterInfo) {
|
||||
return -1;
|
||||
adapter_addresses = (IP_ADAPTER_ADDRESSES *)malloc(adapter_addresses_length);
|
||||
if (!adapter_addresses) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ULONG LengthNeeded = AdapterInfoLength;
|
||||
DWORD Ret = GetAdaptersInfo(AdapterInfo, &LengthNeeded);
|
||||
if (Ret == NO_ERROR) {
|
||||
ULONG length_needed = adapter_addresses_length;
|
||||
DWORD ret = GetAdaptersAddresses(af, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, adapter_addresses, &length_needed);
|
||||
if (ret == NO_ERROR) {
|
||||
break;
|
||||
}
|
||||
|
||||
free(AdapterInfo);
|
||||
free(adapter_addresses);
|
||||
|
||||
if (Ret != ERROR_BUFFER_OVERFLOW) {
|
||||
return -1;
|
||||
if (ret != ERROR_BUFFER_OVERFLOW) {
|
||||
return false;
|
||||
}
|
||||
if (AdapterInfoLength >= LengthNeeded) {
|
||||
return -1;
|
||||
if (adapter_addresses_length >= length_needed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AdapterInfoLength = LengthNeeded;
|
||||
adapter_addresses_length = length_needed;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
PIP_ADAPTER_INFO Adapter = AdapterInfo;
|
||||
while (Adapter) {
|
||||
IP_ADDR_STRING *IPAddr = &Adapter->IpAddressList;
|
||||
while (IPAddr) {
|
||||
uint32_t ip_addr = ntohl(inet_addr(IPAddr->IpAddress.String));
|
||||
uint32_t subnet_mask = ntohl(inet_addr(IPAddr->IpMask.String));
|
||||
IP_ADAPTER_ADDRESSES *adapter = adapter_addresses;
|
||||
|
||||
if (ip_addr == 0) {
|
||||
IPAddr = IPAddr->Next;
|
||||
while (adapter) {
|
||||
if ((adapter->IfType != MIB_IF_TYPE_ETHERNET) && (adapter->IfType != IF_TYPE_IEEE80211)) {
|
||||
adapter = adapter->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
if (adapter->PhysicalAddressLength != 6) {
|
||||
adapter = adapter->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
IPAddr = IPAddr->Next;
|
||||
uint32_t ifindex = adapter->IfIndex;
|
||||
|
||||
IP_ADAPTER_UNICAST_ADDRESS *adapter_address = adapter->FirstUnicastAddress;
|
||||
while (adapter_address) {
|
||||
if (adapter_address->Flags & IP_ADAPTER_ADDRESS_TRANSIENT) {
|
||||
adapter_address = adapter_address->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count >= max_count) {
|
||||
break;
|
||||
struct sockaddr *local_ip = adapter_address->Address.lpSockaddr;
|
||||
|
||||
if ((local_ip->sa_family == AF_INET6) && (adapter_address->ValidLifetime != 0xFFFFFFFF)) {
|
||||
adapter_address = adapter_address->Next;
|
||||
continue; /* skip temporary addresses */
|
||||
}
|
||||
|
||||
Adapter = Adapter->Next;
|
||||
uint8_t cidr = adapter_address->OnLinkPrefixLength;
|
||||
callback(callback_arg, ifindex, local_ip, cidr);
|
||||
|
||||
adapter_address = adapter_address->Next;
|
||||
}
|
||||
|
||||
free(AdapterInfo);
|
||||
return count;
|
||||
adapter = adapter->Next;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol)
|
||||
free(adapter_addresses);
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int af, int protocol)
|
||||
{
|
||||
struct hdhomerun_sock_t *sock = (struct hdhomerun_sock_t *)calloc(1, sizeof(struct hdhomerun_sock_t));
|
||||
if (!sock) {
|
||||
|
@ -151,7 +106,7 @@ static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol)
|
|||
}
|
||||
|
||||
/* Create socket. */
|
||||
sock->sock = socket(AF_INET, protocol, 0);
|
||||
sock->sock = socket(af, protocol, 0);
|
||||
if (sock->sock == INVALID_SOCKET) {
|
||||
free(sock);
|
||||
return NULL;
|
||||
|
@ -164,6 +119,12 @@ static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Set ipv6 */
|
||||
if (af == AF_INET6) {
|
||||
int sock_opt_ipv6only = 1;
|
||||
setsockopt(sock->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&sock_opt_ipv6only, sizeof(sock_opt_ipv6only));
|
||||
}
|
||||
|
||||
/* Event */
|
||||
sock->event = CreateEvent(NULL, false, false, NULL);
|
||||
if (!sock->event) {
|
||||
|
@ -175,9 +136,9 @@ static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol)
|
|||
return sock;
|
||||
}
|
||||
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void)
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_udp_ex(int af)
|
||||
{
|
||||
struct hdhomerun_sock_t *sock = hdhomerun_sock_create_internal(SOCK_DGRAM);
|
||||
struct hdhomerun_sock_t *sock = hdhomerun_sock_create_internal(af, SOCK_DGRAM);
|
||||
if (!sock) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -190,9 +151,9 @@ struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void)
|
|||
return sock;
|
||||
}
|
||||
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_tcp(void)
|
||||
struct hdhomerun_sock_t *hdhomerun_sock_create_tcp_ex(int af)
|
||||
{
|
||||
return hdhomerun_sock_create_internal(SOCK_STREAM);
|
||||
return hdhomerun_sock_create_internal(af, SOCK_STREAM);
|
||||
}
|
||||
|
||||
void hdhomerun_sock_destroy(struct hdhomerun_sock_t *sock)
|
||||
|
@ -228,73 +189,77 @@ 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_ipv4_onesbcast(struct hdhomerun_sock_t *sock, int v)
|
||||
{
|
||||
}
|
||||
|
||||
void hdhomerun_sock_set_ipv6_multicast_ifindex(struct hdhomerun_sock_t *sock, uint32_t ifindex)
|
||||
{
|
||||
setsockopt(sock->sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&ifindex, sizeof(ifindex));
|
||||
}
|
||||
|
||||
int hdhomerun_sock_getlasterror(void)
|
||||
{
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getsockname_addr(struct hdhomerun_sock_t *sock)
|
||||
bool hdhomerun_sock_getsockname_addr_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *result)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
int sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ntohl(sock_addr.sin_addr.s_addr);
|
||||
socklen_t sockaddr_size = sizeof(struct sockaddr_storage);
|
||||
return (getsockname(sock->sock, (struct sockaddr *)result, &sockaddr_size) == 0);
|
||||
}
|
||||
|
||||
uint16_t hdhomerun_sock_getsockname_port(struct hdhomerun_sock_t *sock)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
int sockaddr_size = sizeof(sock_addr);
|
||||
struct sockaddr_storage sock_addr;
|
||||
socklen_t sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ntohs(sock_addr.sin_port);
|
||||
if (sock_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&sock_addr;
|
||||
return ntohs(sock_addr_in->sin_port);
|
||||
}
|
||||
if (sock_addr.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sock_addr_in = (struct sockaddr_in6 *)&sock_addr;
|
||||
return ntohs(sock_addr_in->sin6_port);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getpeername_addr(struct hdhomerun_sock_t *sock)
|
||||
{
|
||||
struct sockaddr_in sock_addr;
|
||||
int sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
if (getpeername(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ntohl(sock_addr.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
uint32_t hdhomerun_sock_getaddrinfo_addr(struct hdhomerun_sock_t *sock, const char *name)
|
||||
bool hdhomerun_sock_getpeername_addr_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *result)
|
||||
{
|
||||
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(name, NULL, &hints, &sock_info) != 0) {
|
||||
return 0;
|
||||
socklen_t sockaddr_size = sizeof(struct sockaddr_storage);
|
||||
return (getpeername(sock->sock, (struct sockaddr *)result, &sockaddr_size) == 0);
|
||||
}
|
||||
|
||||
struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr;
|
||||
uint32_t addr = ntohl(sock_addr->sin_addr.s_addr);
|
||||
|
||||
freeaddrinfo(sock_info);
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip)
|
||||
bool hdhomerun_sock_join_multicast_group_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr)
|
||||
{
|
||||
if (multicast_addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *multicast_addr_in = (const struct sockaddr_in6 *)multicast_addr;
|
||||
|
||||
struct ipv6_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
memcpy(imr.ipv6mr_multiaddr.s6_addr, multicast_addr_in->sin6_addr.s6_addr, 16);
|
||||
imr.ipv6mr_interface = multicast_addr_in->sin6_scope_id;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (multicast_addr->sa_family == AF_INET) {
|
||||
const struct sockaddr_in *multicast_addr_in = (const struct sockaddr_in *)multicast_addr;
|
||||
const struct sockaddr_in *local_addr_in = (const struct sockaddr_in *)local_addr;
|
||||
|
||||
struct ip_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
imr.imr_multiaddr.s_addr = htonl(multicast_ip);
|
||||
imr.imr_interface.s_addr = htonl(local_ip);
|
||||
imr.imr_multiaddr.s_addr = multicast_addr_in->sin_addr.s_addr;
|
||||
imr.imr_interface.s_addr = (local_addr->sa_family == AF_INET) ? local_addr_in->sin_addr.s_addr : 0;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
|
@ -303,12 +268,34 @@ bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_leave_multicast_group_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr)
|
||||
{
|
||||
if (multicast_addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *multicast_addr_in = (const struct sockaddr_in6 *)multicast_addr;
|
||||
|
||||
struct ipv6_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
memcpy(imr.ipv6mr_multiaddr.s6_addr, multicast_addr_in->sin6_addr.s6_addr, 16);
|
||||
imr.ipv6mr_interface = multicast_addr_in->sin6_scope_id;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (multicast_addr->sa_family == AF_INET) {
|
||||
const struct sockaddr_in *multicast_addr_in = (const struct sockaddr_in *)multicast_addr;
|
||||
const struct sockaddr_in *local_addr_in = (const struct sockaddr_in *)local_addr;
|
||||
|
||||
struct ip_mreq imr;
|
||||
memset(&imr, 0, sizeof(imr));
|
||||
imr.imr_multiaddr.s_addr = htonl(multicast_ip);
|
||||
imr.imr_interface.s_addr = htonl(local_ip);
|
||||
imr.imr_multiaddr.s_addr = multicast_addr_in->sin_addr.s_addr;
|
||||
imr.imr_interface.s_addr = (local_addr->sa_family == AF_INET) ? local_addr_in->sin_addr.s_addr : 0;
|
||||
|
||||
if (setsockopt(sock->sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) {
|
||||
return false;
|
||||
|
@ -317,18 +304,27 @@ bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_
|
|||
return true;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_bind(struct hdhomerun_sock_t *sock, uint32_t local_addr, uint16_t local_port, bool allow_reuse)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_bind_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *local_addr, bool allow_reuse)
|
||||
{
|
||||
socklen_t local_addr_size;
|
||||
switch (local_addr->sa_family) {
|
||||
case AF_INET6:
|
||||
local_addr_size = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
case AF_INET:
|
||||
local_addr_size = (socklen_t)sizeof(struct sockaddr_in);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
int sock_opt = allow_reuse;
|
||||
setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt));
|
||||
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(local_addr);
|
||||
sock_addr.sin_port = htons(local_port);
|
||||
|
||||
if (bind(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
|
||||
if (bind(sock->sock, (const struct sockaddr *)local_addr, local_addr_size) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -348,19 +344,25 @@ static bool hdhomerun_sock_event_select(struct hdhomerun_sock_t *sock, long even
|
|||
return true;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_connect(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout)
|
||||
bool hdhomerun_sock_connect_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *remote_addr, uint64_t timeout)
|
||||
{
|
||||
socklen_t remote_addr_size;
|
||||
switch (remote_addr->sa_family) {
|
||||
case AF_INET6:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
case AF_INET:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hdhomerun_sock_event_select(sock, FD_WRITE | FD_CLOSE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(remote_addr);
|
||||
sock_addr.sin_port = htons(remote_port);
|
||||
|
||||
if (connect(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
|
||||
if (connect(sock->sock, remote_addr, remote_addr_size) != 0) {
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
||||
return false;
|
||||
}
|
||||
|
@ -420,19 +422,25 @@ bool hdhomerun_sock_send(struct hdhomerun_sock_t *sock, const void *data, size_t
|
|||
}
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout)
|
||||
bool hdhomerun_sock_sendto_ex(struct hdhomerun_sock_t *sock, const struct sockaddr *remote_addr, const void *data, size_t length, uint64_t timeout)
|
||||
{
|
||||
socklen_t remote_addr_size;
|
||||
switch (remote_addr->sa_family) {
|
||||
case AF_INET6:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
case AF_INET:
|
||||
remote_addr_size = (socklen_t)sizeof(struct sockaddr_in);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hdhomerun_sock_event_select(sock, FD_WRITE | FD_CLOSE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(remote_addr);
|
||||
sock_addr.sin_port = htons(remote_port);
|
||||
|
||||
int ret = sendto(sock->sock, (char *)data, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
|
||||
int ret = sendto(sock->sock, (char *)data, (int)length, 0, remote_addr, remote_addr_size);
|
||||
if (ret >= (int)length) {
|
||||
return true;
|
||||
}
|
||||
|
@ -448,7 +456,7 @@ bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr,
|
|||
return false;
|
||||
}
|
||||
|
||||
ret = sendto(sock->sock, (char *)data, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
|
||||
ret = sendto(sock->sock, (char *)data, (int)length, 0, remote_addr, remote_addr_size);
|
||||
if (ret >= (int)length) {
|
||||
return true;
|
||||
}
|
||||
|
@ -488,20 +496,15 @@ bool hdhomerun_sock_recv(struct hdhomerun_sock_t *sock, void *data, size_t *leng
|
|||
return false;
|
||||
}
|
||||
|
||||
bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout)
|
||||
bool hdhomerun_sock_recvfrom_ex(struct hdhomerun_sock_t *sock, struct sockaddr_storage *remote_addr, void *data, size_t *length, uint64_t timeout)
|
||||
{
|
||||
if (!hdhomerun_sock_event_select(sock, FD_READ | FD_CLOSE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
int sockaddr_size = sizeof(sock_addr);
|
||||
|
||||
int ret = recvfrom(sock->sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
|
||||
socklen_t sockaddr_size = sizeof(struct sockaddr_storage);
|
||||
int ret = recvfrom(sock->sock, (char *)data, (int)(*length), 0, (struct sockaddr *)remote_addr, &sockaddr_size);
|
||||
if (ret > 0) {
|
||||
*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
|
||||
*remote_port = ntohs(sock_addr.sin_port);
|
||||
*length = ret;
|
||||
return true;
|
||||
}
|
||||
|
@ -517,10 +520,8 @@ bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_add
|
|||
return false;
|
||||
}
|
||||
|
||||
ret = recvfrom(sock->sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
|
||||
ret = recvfrom(sock->sock, (char *)data, (int)(*length), 0, (struct sockaddr *)remote_addr, &sockaddr_size);
|
||||
if (ret > 0) {
|
||||
*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
|
||||
*remote_port = ntohs(sock_addr.sin_port);
|
||||
*length = ret;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_video.c
|
||||
*
|
||||
* Copyright © 2006-2016 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -26,8 +26,7 @@ struct hdhomerun_video_sock_t {
|
|||
struct hdhomerun_sock_t *sock;
|
||||
|
||||
uint32_t keepalive_lockkey;
|
||||
uint32_t keepalive_addr;
|
||||
uint16_t keepalive_port;
|
||||
struct sockaddr_storage keepalive_addr;
|
||||
volatile bool keepalive_start;
|
||||
|
||||
volatile size_t head;
|
||||
|
@ -52,6 +51,16 @@ struct hdhomerun_video_sock_t {
|
|||
static void hdhomerun_video_thread_execute(void *arg);
|
||||
|
||||
struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, bool allow_port_reuse, size_t buffer_size, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
struct sockaddr_in listen_addr_in;
|
||||
memset(&listen_addr_in, 0, sizeof(listen_addr_in));
|
||||
listen_addr_in.sin_family = AF_INET;
|
||||
listen_addr_in.sin_port = htons(listen_port);
|
||||
|
||||
return hdhomerun_video_create_ex((const struct sockaddr *)&listen_addr_in, allow_port_reuse, buffer_size, dbg);
|
||||
}
|
||||
|
||||
struct hdhomerun_video_sock_t *hdhomerun_video_create_ex(const struct sockaddr *listen_addr, bool allow_port_reuse, size_t buffer_size, struct hdhomerun_debug_t *dbg)
|
||||
{
|
||||
/* Create object. */
|
||||
struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)calloc(1, sizeof(struct hdhomerun_video_sock_t));
|
||||
|
@ -82,7 +91,7 @@ struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, bool
|
|||
}
|
||||
|
||||
/* Create socket. */
|
||||
vs->sock = hdhomerun_sock_create_udp();
|
||||
vs->sock = hdhomerun_sock_create_udp_ex(listen_addr->sa_family);
|
||||
if (!vs->sock) {
|
||||
hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate socket\n");
|
||||
goto error;
|
||||
|
@ -92,8 +101,8 @@ struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, bool
|
|||
hdhomerun_sock_set_recv_buffer_size(vs->sock, 1024 * 1024);
|
||||
|
||||
/* Bind socket. */
|
||||
if (!hdhomerun_sock_bind(vs->sock, INADDR_ANY, listen_port, allow_port_reuse)) {
|
||||
hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to bind socket (port %u)\n", listen_port);
|
||||
if (!hdhomerun_sock_bind_ex(vs->sock, listen_addr, allow_port_reuse)) {
|
||||
hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to bind socket\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -134,14 +143,36 @@ void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs)
|
|||
}
|
||||
|
||||
void hdhomerun_video_set_keepalive(struct hdhomerun_video_sock_t *vs, uint32_t remote_addr, uint16_t remote_port, uint32_t lockkey)
|
||||
{
|
||||
if ((remote_addr == 0) || (remote_port == 0)) {
|
||||
hdhomerun_video_set_keepalive_ex(vs, NULL, lockkey);
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in remote_addr_in;
|
||||
memset(&remote_addr_in, 0, sizeof(remote_addr_in));
|
||||
remote_addr_in.sin_family = AF_INET;
|
||||
remote_addr_in.sin_addr.s_addr = htonl(remote_addr);
|
||||
remote_addr_in.sin_port = htons(remote_port);
|
||||
|
||||
hdhomerun_video_set_keepalive_ex(vs, (struct sockaddr *)&remote_addr_in, lockkey);
|
||||
}
|
||||
|
||||
void hdhomerun_video_set_keepalive_ex(struct hdhomerun_video_sock_t *vs, const struct sockaddr *remote_addr, uint32_t lockkey)
|
||||
{
|
||||
thread_mutex_lock(&vs->lock);
|
||||
|
||||
vs->keepalive_addr = remote_addr;
|
||||
vs->keepalive_port = remote_port;
|
||||
memset(&vs->keepalive_addr, 0, sizeof(vs->keepalive_addr));
|
||||
if (remote_addr && (remote_addr->sa_family == AF_INET6)) {
|
||||
memcpy(&vs->keepalive_addr, remote_addr, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
if (remote_addr && (remote_addr->sa_family == AF_INET)) {
|
||||
memcpy(&vs->keepalive_addr, remote_addr, sizeof(struct sockaddr_in));
|
||||
}
|
||||
|
||||
vs->keepalive_lockkey = lockkey;
|
||||
|
||||
if ((remote_addr != 0) && (remote_port != 0)) {
|
||||
if (vs->keepalive_addr.ss_family) {
|
||||
vs->keepalive_start = true;
|
||||
}
|
||||
|
||||
|
@ -166,7 +197,22 @@ uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs)
|
|||
|
||||
int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip)
|
||||
{
|
||||
if (!hdhomerun_sock_join_multicast_group(vs->sock, multicast_ip, local_ip)) {
|
||||
struct sockaddr_in multicast_addr;
|
||||
memset(&multicast_addr, 0, sizeof(multicast_addr));
|
||||
multicast_addr.sin_family = AF_INET;
|
||||
multicast_addr.sin_addr.s_addr = htonl(multicast_ip);
|
||||
|
||||
struct sockaddr_in local_addr;
|
||||
memset(&local_addr, 0, sizeof(local_addr));
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_addr.s_addr = htonl(local_ip);
|
||||
|
||||
return hdhomerun_video_join_multicast_group_ex(vs, (struct sockaddr *)&multicast_addr, (struct sockaddr *)&local_addr);
|
||||
}
|
||||
|
||||
int hdhomerun_video_join_multicast_group_ex(struct hdhomerun_video_sock_t *vs, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr)
|
||||
{
|
||||
if (!hdhomerun_sock_join_multicast_group_ex(vs->sock, multicast_addr, local_addr)) {
|
||||
hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_join_multicast_group: setsockopt failed (%d)\n", hdhomerun_sock_getlasterror());
|
||||
return -1;
|
||||
}
|
||||
|
@ -176,7 +222,22 @@ int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint
|
|||
|
||||
void hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip)
|
||||
{
|
||||
if (!hdhomerun_sock_leave_multicast_group(vs->sock, multicast_ip, local_ip)) {
|
||||
struct sockaddr_in multicast_addr;
|
||||
memset(&multicast_addr, 0, sizeof(multicast_addr));
|
||||
multicast_addr.sin_family = AF_INET;
|
||||
multicast_addr.sin_addr.s_addr = htonl(multicast_ip);
|
||||
|
||||
struct sockaddr_in local_addr;
|
||||
memset(&local_addr, 0, sizeof(local_addr));
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_addr.s_addr = htonl(local_ip);
|
||||
|
||||
hdhomerun_video_leave_multicast_group_ex(vs, (struct sockaddr *)&multicast_addr, (struct sockaddr *)&local_addr);
|
||||
}
|
||||
|
||||
void hdhomerun_video_leave_multicast_group_ex(struct hdhomerun_video_sock_t *vs, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr)
|
||||
{
|
||||
if (!hdhomerun_sock_leave_multicast_group_ex(vs->sock, multicast_addr, local_addr)) {
|
||||
hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_leave_multicast_group: setsockopt failed (%d)\n", hdhomerun_sock_getlasterror());
|
||||
}
|
||||
}
|
||||
|
@ -251,19 +312,19 @@ static void hdhomerun_video_thread_send_keepalive(struct hdhomerun_video_sock_t
|
|||
{
|
||||
thread_mutex_lock(&vs->lock);
|
||||
uint32_t keepalive_lockkey = vs->keepalive_lockkey;
|
||||
uint32_t keepalive_addr = vs->keepalive_addr;
|
||||
uint16_t keepalive_port = vs->keepalive_port;
|
||||
struct sockaddr_storage keepalive_addr;
|
||||
keepalive_addr = vs->keepalive_addr;
|
||||
vs->keepalive_start = false;
|
||||
thread_mutex_unlock(&vs->lock);
|
||||
|
||||
if ((keepalive_addr == 0) || (keepalive_port == 0)) {
|
||||
if (keepalive_addr.ss_family == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct hdhomerun_pkt_t pkt;
|
||||
hdhomerun_pkt_reset(&pkt);
|
||||
hdhomerun_pkt_write_u32(&pkt, keepalive_lockkey);
|
||||
hdhomerun_sock_sendto(vs->sock, keepalive_addr, keepalive_port, pkt.start, pkt.end - pkt.start, 25);
|
||||
hdhomerun_sock_sendto_ex(vs->sock, (struct sockaddr *)&keepalive_addr, pkt.start, pkt.end - pkt.start, 25);
|
||||
}
|
||||
|
||||
static void hdhomerun_video_thread_execute(void *arg)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* hdhomerun_video.h
|
||||
*
|
||||
* Copyright © 2006-2016 Silicondust USA Inc. <www.silicondust.com>.
|
||||
* Copyright © 2006-2022 Silicondust USA Inc. <www.silicondust.com>.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -49,12 +49,14 @@ struct hdhomerun_video_stats_t {
|
|||
* When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, bool allow_port_reuse, size_t buffer_size, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API struct hdhomerun_video_sock_t *hdhomerun_video_create_ex(const struct sockaddr *listen_addr, bool allow_port_reuse, size_t buffer_size, struct hdhomerun_debug_t *dbg);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs);
|
||||
|
||||
/*
|
||||
* Configure to send a keepalive packet every second.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API void hdhomerun_video_set_keepalive(struct hdhomerun_video_sock_t *vs, uint32_t remote_addr, uint16_t remote_port, uint32_t lockkey);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_video_set_keepalive_ex(struct hdhomerun_video_sock_t *vs, const struct sockaddr *remote_addr, uint32_t lockkey);
|
||||
|
||||
/*
|
||||
* Get the port the socket is listening on.
|
||||
|
@ -67,7 +69,9 @@ extern LIBHDHOMERUN_API uint16_t hdhomerun_video_get_local_port(struct hdhomerun
|
|||
* Join/leave multicast group.
|
||||
*/
|
||||
extern LIBHDHOMERUN_API int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip);
|
||||
extern LIBHDHOMERUN_API int hdhomerun_video_join_multicast_group_ex(struct hdhomerun_video_sock_t *vs, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip);
|
||||
extern LIBHDHOMERUN_API void hdhomerun_video_leave_multicast_group_ex(struct hdhomerun_video_sock_t *vs, const struct sockaddr *multicast_addr, const struct sockaddr *local_addr);
|
||||
|
||||
/*
|
||||
* Read data from buffer.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue