Ticket #8387: libmythhdhomerun.2.patch
File libmythhdhomerun.2.patch, 133.8 KB (added by , 15 years ago) |
---|
-
hdhomerun_control.h
1 1 /* 2 2 * hdhomerun_control.h 3 3 * 4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public -
hdhomerun.h
1 #ifndef __HDHOMERUN_INCLUDES__2 #define __HDHOMERUN_INCLUDES__3 1 /* 4 2 * hdhomerun.h 5 3 * 6 * Copyright © 2006-2008Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 7 5 * 8 6 * This library is free software; you can redistribute it and/or 9 7 * modify it under the terms of the GNU Lesser General Public … … 35 33 #include "hdhomerun_os.h" 36 34 #include "hdhomerun_types.h" 37 35 #include "hdhomerun_pkt.h" 36 #include "hdhomerun_sock.h" 38 37 #include "hdhomerun_debug.h" 39 38 #include "hdhomerun_discover.h" 40 39 #include "hdhomerun_control.h" … … 43 42 #include "hdhomerun_channelscan.h" 44 43 #include "hdhomerun_device.h" 45 44 #include "hdhomerun_device_selector.h" 46 47 #endif /* __HDHOMERUN_INCLUDES__ */ -
hdhomerun_debug.c
1 1 /* 2 2 * hdhomerun_debug.c 3 3 * 4 * Copyright © 2006Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 44 44 #define HDHOMERUN_DEBUG_HOST "debug.silicondust.com" 45 45 #endif 46 46 #if !defined(HDHOMERUN_DEBUG_PORT) 47 #define HDHOMERUN_DEBUG_PORT "8002"47 #define HDHOMERUN_DEBUG_PORT 8002 48 48 #endif 49 49 50 #define HDHOMERUN_DEBUG_CONNECT_RETRY_TIME 30000 51 #define HDHOMERUN_DEBUG_CONNECT_TIMEOUT 10000 52 #define HDHOMERUN_DEBUG_SEND_TIMEOUT 10000 53 50 54 struct hdhomerun_debug_message_t 51 55 { 52 56 struct hdhomerun_debug_message_t *next; … … 73 77 74 78 char *file_name; 75 79 FILE *file_fp; 76 int sock;80 hdhomerun_sock_t sock; 77 81 }; 78 82 79 83 static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg); … … 85 89 return NULL; 86 90 } 87 91 88 dbg->sock = -1;92 dbg->sock = HDHOMERUN_SOCK_INVALID; 89 93 90 94 pthread_mutex_init(&dbg->print_lock, NULL); 91 95 pthread_mutex_init(&dbg->queue_lock, NULL); … … 117 121 if (dbg->file_fp) { 118 122 fclose(dbg->file_fp); 119 123 } 120 if (dbg->sock != -1) {121 close(dbg->sock);124 if (dbg->sock != HDHOMERUN_SOCK_INVALID) { 125 hdhomerun_sock_destroy(dbg->sock); 122 126 } 123 127 124 128 free(dbg); … … 132 136 dbg->file_fp = NULL; 133 137 } 134 138 135 if (dbg->sock != -1) {136 close(dbg->sock);137 dbg->sock = -1;139 if (dbg->sock != HDHOMERUN_SOCK_INVALID) { 140 hdhomerun_sock_destroy(dbg->sock); 141 dbg->sock = HDHOMERUN_SOCK_INVALID; 138 142 } 139 143 } 140 144 … … 251 255 return; 252 256 } 253 257 254 msleep (10);258 msleep_approx(10); 255 259 } 256 260 } 257 261 … … 372 376 } 373 377 374 378 /* Send lock held by caller */ 375 #if defined(__CYGWIN__)376 379 static bool_t hdhomerun_debug_output_message_sock(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) 377 380 { 378 return TRUE; 379 } 380 #else 381 static bool_t hdhomerun_debug_output_message_sock(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) 382 { 383 if (dbg->sock == -1) { 381 if (dbg->sock == HDHOMERUN_SOCK_INVALID) { 384 382 uint64_t current_time = getcurrenttime(); 385 383 if (current_time < dbg->connect_delay) { 386 384 return FALSE; 387 385 } 388 dbg->connect_delay = current_time + 30*1000;386 dbg->connect_delay = current_time + HDHOMERUN_DEBUG_CONNECT_RETRY_TIME; 389 387 390 dbg->sock = (int)socket(AF_INET, SOCK_STREAM, 0);391 if (dbg->sock == -1) {388 dbg->sock = hdhomerun_sock_create_tcp(); 389 if (dbg->sock == HDHOMERUN_SOCK_INVALID) { 392 390 return FALSE; 393 391 } 394 392 395 struct addrinfo hints; 396 memset(&hints, 0, sizeof(hints)); 397 hints.ai_family = AF_INET; 398 hints.ai_socktype = SOCK_STREAM; 399 hints.ai_protocol = IPPROTO_TCP; 400 401 struct addrinfo *sock_info; 402 if (getaddrinfo(HDHOMERUN_DEBUG_HOST, HDHOMERUN_DEBUG_PORT, &hints, &sock_info) != 0) { 393 uint32_t remote_addr = hdhomerun_sock_getaddrinfo_addr(dbg->sock, HDHOMERUN_DEBUG_HOST); 394 if (remote_addr == 0) { 403 395 hdhomerun_debug_close_internal(dbg); 404 396 return FALSE; 405 397 } 406 if (connect(dbg->sock, sock_info->ai_addr, (int)sock_info->ai_addrlen) != 0) { 407 freeaddrinfo(sock_info);398 399 if (!hdhomerun_sock_connect(dbg->sock, remote_addr, HDHOMERUN_DEBUG_PORT, HDHOMERUN_DEBUG_CONNECT_TIMEOUT)) { 408 400 hdhomerun_debug_close_internal(dbg); 409 401 return FALSE; 410 402 } 411 freeaddrinfo(sock_info);412 403 } 413 404 414 405 size_t length = strlen(message->buffer); 415 if ( send(dbg->sock, (char *)message->buffer, (int)length, 0) != length) {406 if (!hdhomerun_sock_send(dbg->sock, message->buffer, length, HDHOMERUN_DEBUG_SEND_TIMEOUT)) { 416 407 hdhomerun_debug_close_internal(dbg); 417 408 return FALSE; 418 409 } 419 410 420 411 return TRUE; 421 412 } 422 #endif423 413 424 414 static bool_t hdhomerun_debug_output_message(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) 425 415 { … … 466 456 pthread_mutex_unlock(&dbg->queue_lock); 467 457 468 458 if (!message) { 469 msleep (250);459 msleep_approx(250); 470 460 continue; 471 461 } 472 462 … … 476 466 } 477 467 478 468 if (!hdhomerun_debug_output_message(dbg, message)) { 479 msleep (250);469 msleep_approx(250); 480 470 continue; 481 471 } 482 472 -
libmythhdhomerun.pro
10 10 11 11 QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2) 12 12 13 HEADERS += hdhomerun.h hdhomerun_os.h hdhomerun_ types.h13 HEADERS += hdhomerun.h hdhomerun_os.h hdhomerun_sock.h hdhomerun_types.h 14 14 15 15 HEADERS += hdhomerun_channels.h hdhomerun_channelscan.h hdhomerun_control.h 16 HEADERS += hdhomerun_debug.h hdhomerun_device.h hdhomerun_d hcp.h16 HEADERS += hdhomerun_debug.h hdhomerun_device.h hdhomerun_device_selector.h 17 17 HEADERS += hdhomerun_discover.h hdhomerun_pkt.h hdhomerun_video.h 18 HEADERS += hdhomerun_device_selector.h19 18 20 19 SOURCES += hdhomerun_channels.c hdhomerun_channelscan.c hdhomerun_control.c 21 SOURCES += hdhomerun_debug.c hdhomerun_device.c hdhomerun_d hcp.c20 SOURCES += hdhomerun_debug.c hdhomerun_device.c hdhomerun_device_selector.c 22 21 SOURCES += hdhomerun_discover.c hdhomerun_pkt.c hdhomerun_video.c 23 SOURCES += hdhomerun_device_selector.c24 22 23 unix { 24 HEADERS += hdhomerun_os_posix.h hdhomerun_sock_posix.h 25 SOURCES += hdhomerun_os_posix.c hdhomerun_sock_posix.c 26 } 27 25 28 mingw { 26 HEADERS += hdhomerun_os_windows.h 29 HEADERS += hdhomerun_os_windows.h hdhomerun_sock_windows.h 30 SOURCES += hdhomerun_os_windows.c hdhomerun_sock_windows.c 27 31 LIBS += -lws2_32 -liphlpapi -lpthread 28 32 } 29 33 -
hdhomerun_debug.h
1 1 /* 2 2 * hdhomerun_debug.h 3 3 * 4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public -
hdhomerun_os_posix.c
1 /* 2 * hdhomerun_os_posix.c 3 * 4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 3 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * As a special exception to the GNU Lesser General Public License, 20 * you may link, statically or dynamically, an application with a 21 * publicly distributed version of the Library to produce an 22 * executable file containing portions of the Library, and 23 * distribute that executable file under terms of your choice, 24 * without any of the additional requirements listed in clause 4 of 25 * the GNU Lesser General Public License. 26 * 27 * By "a publicly distributed version of the Library", we mean 28 * either the unmodified Library as distributed by Silicondust, or a 29 * modified version of the Library that is distributed under the 30 * conditions defined in the GNU Lesser General Public License. 31 */ 32 33 #include "hdhomerun_os.h" 34 35 uint64_t getcurrenttime(void) 36 { 37 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 38 static uint64_t result = 0; 39 static uint64_t previous_time = 0; 40 41 pthread_mutex_lock(&lock); 42 43 #if defined(CLOCK_MONOTONIC) 44 struct timespec tp; 45 clock_gettime(CLOCK_MONOTONIC, &tp); 46 uint64_t current_time = ((uint64_t)tp.tv_sec * 1000) + (tp.tv_nsec / 1000000); 47 #else 48 struct timeval t; 49 gettimeofday(&t, NULL); 50 uint64_t current_time = ((uint64_t)t.tv_sec * 1000) + (t.tv_usec / 1000); 51 #endif 52 53 if (current_time > previous_time) { 54 result += current_time - previous_time; 55 } 56 57 previous_time = current_time; 58 59 pthread_mutex_unlock(&lock); 60 return result; 61 } 62 63 void msleep_approx(uint64_t ms) 64 { 65 unsigned int delay_s = ms / 1000; 66 if (delay_s > 0) { 67 sleep(delay_s); 68 ms -= delay_s * 1000; 69 } 70 71 unsigned int delay_us = ms * 1000; 72 if (delay_us > 0) { 73 usleep(delay_us); 74 } 75 } 76 77 void msleep_minimum(uint64_t ms) 78 { 79 uint64_t stop_time = getcurrenttime() + ms; 80 81 while (1) { 82 uint64_t current_time = getcurrenttime(); 83 if (current_time >= stop_time) { 84 return; 85 } 86 87 msleep_approx(stop_time - current_time); 88 } 89 } -
hdhomerun_sock.h
Property changes on: hdhomerun_os_posix.c ___________________________________________________________________ Added: svn:executable + *
1 /* 2 * hdhomerun_sock.h 3 * 4 * Copyright © 2010 Silicondust USA Inc. <www.silicondust.com>. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 3 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * As a special exception to the GNU Lesser General Public License, 20 * you may link, statically or dynamically, an application with a 21 * publicly distributed version of the Library to produce an 22 * executable file containing portions of the Library, and 23 * distribute that executable file under terms of your choice, 24 * without any of the additional requirements listed in clause 4 of 25 * the GNU Lesser General Public License. 26 * 27 * By "a publicly distributed version of the Library", we mean 28 * either the unmodified Library as distributed by Silicondust, or a 29 * modified version of the Library that is distributed under the 30 * conditions defined in the GNU Lesser General Public License. 31 */ 32 #ifdef __cplusplus 33 extern "C" { 34 #endif 35 36 #define HDHOMERUN_SOCK_INVALID -1 37 38 typedef int hdhomerun_sock_t; 39 40 extern LIBTYPE hdhomerun_sock_t hdhomerun_sock_create_udp(void); 41 extern LIBTYPE hdhomerun_sock_t hdhomerun_sock_create_tcp(void); 42 extern LIBTYPE void hdhomerun_sock_destroy(hdhomerun_sock_t sock); 43 44 extern LIBTYPE int hdhomerun_sock_getlasterror(void); 45 extern LIBTYPE uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock); 46 extern LIBTYPE uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock); 47 extern LIBTYPE uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock); 48 extern LIBTYPE uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name); 49 50 extern LIBTYPE bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port); 51 extern LIBTYPE bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout); 52 53 extern LIBTYPE bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout); 54 extern LIBTYPE bool_t hdhomerun_sock_sendto(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout); 55 56 extern LIBTYPE bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout); 57 extern LIBTYPE bool_t hdhomerun_sock_recvfrom(hdhomerun_sock_t sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout); 58 59 60 #ifdef __cplusplus 61 } 62 #endif -
hdhomerun_config.c
Property changes on: hdhomerun_sock.h ___________________________________________________________________ Added: svn:executable + *
1 1 /* 2 2 * hdhomerun_config.c 3 3 * 4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 202 202 return cmd_set_internal(item, value); 203 203 } 204 204 205 static bool_t sigabort = FALSE; 205 static volatile sig_atomic_t sigabort_flag = FALSE; 206 static volatile sig_atomic_t siginfo_flag = FALSE; 207 208 static void sigabort_handler(int arg) 209 { 210 sigabort_flag = TRUE; 211 } 206 212 207 static void sig nal_abort(int arg)213 static void siginfo_handler(int arg) 208 214 { 209 sig abort= TRUE;215 siginfo_flag = TRUE; 210 216 } 211 217 218 static void register_signal_handlers(sig_t sigpipe_handler, sig_t sigint_handler, sig_t siginfo_handler) 219 { 220 #if defined(SIGPIPE) 221 signal(SIGPIPE, sigpipe_handler); 222 #endif 223 #if defined(SIGINT) 224 signal(SIGINT, sigint_handler); 225 #endif 226 #if defined(SIGINFO) 227 signal(SIGINFO, siginfo_handler); 228 #endif 229 } 230 212 231 static void cmd_scan_printf(FILE *fp, const char *fmt, ...) 213 232 { 214 233 va_list ap; … … 274 293 } 275 294 } 276 295 277 signal(SIGINT, signal_abort); 278 signal(SIGPIPE, signal_abort); 296 register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler); 279 297 280 298 int ret = 0; 281 while (!sigabort ) {299 while (!sigabort_flag) { 282 300 struct hdhomerun_channelscan_result_t result; 283 301 ret = hdhomerun_device_channelscan_advance(hd, &result); 284 302 if (ret <= 0) { … … 286 304 } 287 305 288 306 cmd_scan_printf(fp, "SCANNING: %lu (%s)\n", 289 result.frequency, result.channel_str307 (unsigned long)result.frequency, result.channel_str 290 308 ); 291 309 292 310 ret = hdhomerun_device_channelscan_detect(hd, &result); … … 321 339 return ret; 322 340 } 323 341 342 static void cmd_save_print_stats(void) 343 { 344 struct hdhomerun_video_stats_t stats; 345 hdhomerun_device_get_video_stats(hd, &stats); 346 347 fprintf(stderr, "%u packets received, %u overflow errors, %u network errors, %u transport errors, %u sequence errors\n", 348 (unsigned int)stats.packet_count, 349 (unsigned int)stats.overflow_error_count, 350 (unsigned int)stats.network_error_count, 351 (unsigned int)stats.transport_error_count, 352 (unsigned int)stats.sequence_error_count 353 ); 354 } 355 324 356 static int cmd_save(const char *tuner_str, const char *filename) 325 357 { 326 358 if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) { … … 350 382 return ret; 351 383 } 352 384 353 signal(SIGINT, signal_abort); 354 signal(SIGPIPE, signal_abort); 385 register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler); 355 386 356 387 struct hdhomerun_video_stats_t stats_old, stats_cur; 357 388 hdhomerun_device_get_video_stats(hd, &stats_old); 358 389 359 390 uint64_t next_progress = getcurrenttime() + 1000; 360 391 361 while (!sigabort ) {392 while (!sigabort_flag) { 362 393 uint64_t loop_start_time = getcurrenttime(); 363 394 395 if (siginfo_flag) { 396 fprintf(stderr, "\n"); 397 cmd_save_print_stats(); 398 siginfo_flag = FALSE; 399 } 400 364 401 size_t actual_size; 365 402 uint8_t *ptr = hdhomerun_device_stream_recv(hd, VIDEO_DATA_BUFFER_SIZE_1S, &actual_size); 366 403 if (!ptr) { 367 msleep (64);404 msleep_approx(64); 368 405 continue; 369 406 } 370 407 … … 381 418 next_progress = loop_start_time + 1000; 382 419 } 383 420 421 /* Windows - indicate activity to suppress auto sleep mode. */ 422 #if defined(__WINDOWS__) 423 SetThreadExecutionState(ES_SYSTEM_REQUIRED); 424 #endif 425 426 /* Video stats. */ 384 427 hdhomerun_device_get_video_stats(hd, &stats_cur); 385 428 386 429 if (stats_cur.overflow_error_count > stats_old.overflow_error_count) { … … 404 447 continue; 405 448 } 406 449 407 msleep (delay);450 msleep_approx(delay); 408 451 } 409 452 410 453 if (fp) { … … 412 455 } 413 456 414 457 hdhomerun_device_stream_stop(hd); 415 hdhomerun_device_get_video_stats(hd, &stats_cur);416 458 417 459 fprintf(stderr, "\n"); 418 460 fprintf(stderr, "-- Video statistics --\n"); 419 fprintf(stderr, "%u packets received, %u overflow errors, %u network errors, %u transport errors, %u sequence errors\n", 420 (unsigned int)stats_cur.packet_count, 421 (unsigned int)stats_cur.overflow_error_count, 422 (unsigned int)stats_cur.network_error_count, 423 (unsigned int)stats_cur.transport_error_count, 424 (unsigned int)stats_cur.sequence_error_count); 461 cmd_save_print_stats(); 425 462 426 463 return 0; 427 464 } … … 440 477 fclose(fp); 441 478 return -1; 442 479 } 443 sleep(2);480 msleep_minimum(2000); 444 481 445 482 printf("upgrading firmware...\n"); 446 sleep(8);483 msleep_minimum(8000); 447 484 448 485 printf("rebooting...\n"); 449 486 int count = 0; … … 460 497 return -1; 461 498 } 462 499 463 sleep(1);500 msleep_minimum(1000); 464 501 } 465 502 466 503 printf("upgrade complete - now running firmware %s\n", version_str); -
hdhomerun_video.c
1 1 /* 2 2 * hdhomerun_video.c 3 3 * 4 * Copyright © 2006Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 34 34 35 35 struct hdhomerun_video_sock_t { 36 36 pthread_mutex_t lock; 37 struct hdhomerun_debug_t *dbg; 38 39 hdhomerun_sock_t sock; 40 uint32_t multicast_ip; 41 42 volatile size_t head; 43 volatile size_t tail; 37 44 uint8_t *buffer; 38 45 size_t buffer_size; 39 volatile size_t head;40 volatile size_t tail;41 46 size_t advance; 47 48 pthread_t thread; 42 49 volatile bool_t terminate; 43 pthread_t thread; 44 int sock; 45 uint32_t rtp_sequence; 46 struct hdhomerun_debug_t *dbg; 50 47 51 volatile uint32_t packet_count; 48 52 volatile uint32_t transport_error_count; 49 53 volatile uint32_t network_error_count; 50 54 volatile uint32_t sequence_error_count; 51 55 volatile uint32_t overflow_error_count; 56 57 volatile uint32_t rtp_sequence; 52 58 volatile uint8_t sequence[0x2000]; 53 59 }; 54 60 … … 64 70 } 65 71 66 72 vs->dbg = dbg; 67 vs->sock = -1;73 vs->sock = HDHOMERUN_SOCK_INVALID; 68 74 pthread_mutex_init(&vs->lock, NULL); 69 75 70 76 /* Reset sequence tracking. */ … … 86 92 } 87 93 88 94 /* Create socket. */ 89 vs->sock = (int)socket(AF_INET, SOCK_DGRAM, 0);90 if (vs->sock == -1) {95 vs->sock = hdhomerun_sock_create_udp(); 96 if (vs->sock == HDHOMERUN_SOCK_INVALID) { 91 97 hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate socket\n"); 92 98 goto error; 93 99 } … … 96 102 int rx_size = 1024 * 1024; 97 103 setsockopt(vs->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rx_size, sizeof(rx_size)); 98 104 99 /* Set timeouts. */100 setsocktimeout(vs->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);101 setsocktimeout(vs->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);102 103 105 /* Bind socket. */ 104 struct sockaddr_in sock_addr; 105 memset(&sock_addr, 0, sizeof(sock_addr)); 106 sock_addr.sin_family = AF_INET; 107 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 108 sock_addr.sin_port = htons(listen_port); 109 if (bind(vs->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 106 if (!hdhomerun_sock_bind(vs->sock, INADDR_ANY, listen_port)) { 110 107 hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to bind socket (port %u)\n", listen_port); 111 108 goto error; 112 109 } … … 121 118 return vs; 122 119 123 120 error: 124 if (vs->sock != -1) {125 close(vs->sock);121 if (vs->sock != HDHOMERUN_SOCK_INVALID) { 122 hdhomerun_sock_destroy(vs->sock); 126 123 } 127 124 if (vs->buffer) { 128 125 free(vs->buffer); … … 136 133 vs->terminate = TRUE; 137 134 pthread_join(vs->thread, NULL); 138 135 139 close(vs->sock);136 hdhomerun_sock_destroy(vs->sock); 140 137 free(vs->buffer); 141 138 142 139 free(vs); 143 140 } 144 141 142 hdhomerun_sock_t hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs) 143 { 144 return vs->sock; 145 } 146 145 147 uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs) 146 148 { 147 struct sockaddr_in sock_addr; 148 socklen_t sockaddr_size = sizeof(sock_addr); 149 if (getsockname(vs->sock, (struct sockaddr*)&sock_addr, &sockaddr_size) != 0) { 150 hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_get_local_port: getsockname failed (%d)\n", sock_getlasterror); 149 uint16_t port = hdhomerun_sock_getsockname_port(vs->sock); 150 if (port == 0) { 151 hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_get_local_port: getsockname failed (%d)\n", hdhomerun_sock_getlasterror()); 151 152 return 0; 152 153 } 153 154 154 return ntohs(sock_addr.sin_port);155 return port; 155 156 } 156 157 158 int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip) 159 { 160 if (vs->multicast_ip != 0) { 161 hdhomerun_video_leave_multicast_group(vs); 162 } 163 164 struct ip_mreq imr; 165 memset(&imr, 0, sizeof(imr)); 166 imr.imr_multiaddr.s_addr = htonl(multicast_ip); 167 imr.imr_interface.s_addr = htonl(local_ip); 168 169 if (setsockopt(vs->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { 170 hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_join_multicast_group: setsockopt failed (%d)\n", hdhomerun_sock_getlasterror()); 171 return -1; 172 } 173 174 vs->multicast_ip = multicast_ip; 175 return 1; 176 } 177 178 int hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs) 179 { 180 if (vs->multicast_ip == 0) { 181 return 1; 182 } 183 184 struct ip_mreq imr; 185 memset(&imr, 0, sizeof(imr)); 186 imr.imr_multiaddr.s_addr = htonl(vs->multicast_ip); 187 imr.imr_interface.s_addr = htonl(INADDR_ANY); 188 189 if (setsockopt(vs->sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { 190 hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_leave_multicast_group: setsockopt failed (%d)\n", hdhomerun_sock_getlasterror()); 191 } 192 193 vs->multicast_ip = 0; 194 return 1; 195 } 196 157 197 static void hdhomerun_video_stats_ts_pkt(struct hdhomerun_video_sock_t *vs, uint8_t *ptr) 158 198 { 159 199 uint16_t packet_identifier = ((uint16_t)(ptr[1] & 0x1F) << 8) | (uint16_t)ptr[2]; … … 168 208 return; 169 209 } 170 210 171 uint8_t continuity_counter = ptr[3] & 0x0F; 211 uint8_t sequence = ptr[3] & 0x0F; 212 172 213 uint8_t previous_sequence = vs->sequence[packet_identifier]; 214 vs->sequence[packet_identifier] = sequence; 173 215 174 if (continuity_counter == ((previous_sequence + 1) & 0x0F)) { 175 vs->sequence[packet_identifier] = continuity_counter; 216 if (previous_sequence == 0xFF) { 176 217 return; 177 218 } 178 if (previous_sequence == 0xFF) { 179 vs->sequence[packet_identifier] = continuity_counter; 219 if (sequence == ((previous_sequence + 1) & 0x0F)) { 180 220 return; 181 221 } 182 if ( continuity_counter== previous_sequence) {222 if (sequence == previous_sequence) { 183 223 return; 184 224 } 185 225 186 226 vs->sequence_error_count++; 187 vs->sequence[packet_identifier] = continuity_counter;188 227 } 189 228 190 229 static void hdhomerun_video_parse_rtp(struct hdhomerun_video_sock_t *vs, struct hdhomerun_pkt_t *pkt) … … 193 232 uint32_t rtp_sequence = hdhomerun_pkt_read_u16(pkt); 194 233 pkt->pos += 8; 195 234 196 if (rtp_sequence != ((vs->rtp_sequence + 1) & 0xFFFF)) { 197 if (vs->rtp_sequence != 0xFFFFFFFF) { 198 vs->network_error_count++; 235 uint32_t previous_rtp_sequence = vs->rtp_sequence; 236 vs->rtp_sequence = rtp_sequence; 199 237 200 /* restart pid sequence check */ 201 /* can't use memset bcs sequence is volatile */ 202 int i; 203 for (i = 0; i < sizeof(vs->sequence) / sizeof(uint8_t) ; i++) 204 vs->sequence[i] = 0xFF; 205 } 238 /* Initial case - first packet received. */ 239 if (previous_rtp_sequence == 0xFFFFFFFF) { 240 return; 206 241 } 207 242 208 vs->rtp_sequence = rtp_sequence; 243 /* Normal case - next sequence number. */ 244 if (rtp_sequence == ((previous_rtp_sequence + 1) & 0xFFFF)) { 245 return; 246 } 247 248 /* Error case - sequence missed. */ 249 vs->network_error_count++; 250 251 /* Restart pid sequence check after packet loss. */ 252 int i; 253 for (i = 0; i < 0x2000; i++) { 254 vs->sequence[i] = 0xFF; 255 } 209 256 } 210 257 211 258 static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg) … … 218 265 hdhomerun_pkt_reset(pkt); 219 266 220 267 /* Receive. */ 221 int length = recv(vs->sock, (char *)pkt->end, VIDEO_RTP_DATA_PACKET_SIZE, 0); 268 size_t length = VIDEO_RTP_DATA_PACKET_SIZE; 269 if (!hdhomerun_sock_recv(vs->sock, pkt->end, &length, 25)) { 270 continue; 271 } 272 222 273 pkt->end += length; 223 274 224 275 if (length == VIDEO_RTP_DATA_PACKET_SIZE) { … … 227 278 } 228 279 229 280 if (length != VIDEO_DATA_PACKET_SIZE) { 230 if (length > 0) { 231 /* Data received but not valid - ignore. */ 232 continue; 233 } 234 if (sock_getlasterror_socktimeout) { 235 /* Wait for more data. */ 236 continue; 237 } 238 vs->terminate = TRUE; 239 return NULL; 281 /* Data received but not valid - ignore. */ 282 continue; 240 283 } 241 284 242 285 pthread_mutex_lock(&vs->lock); … … 269 312 continue; 270 313 } 271 314 272 /* Atomic update. */273 315 vs->head = head; 274 316 275 317 pthread_mutex_unlock(&vs->lock); … … 291 333 tail -= vs->buffer_size; 292 334 } 293 335 294 /* Atomic update. */295 336 vs->tail = tail; 296 337 } 297 338 … … 334 375 vs->tail = vs->head; 335 376 vs->advance = 0; 336 377 337 /* can't use memset bcs sequence is volatile */ 378 vs->rtp_sequence = 0xFFFFFFFF; 379 338 380 int i; 339 for (i = 0; i < sizeof(vs->sequence) / sizeof(uint8_t) ; i++)381 for (i = 0; i < 0x2000; i++) { 340 382 vs->sequence[i] = 0xFF; 383 } 341 384 342 vs->rtp_sequence = 0xFFFFFFFF;343 344 385 vs->packet_count = 0; 345 386 vs->transport_error_count = 0; 346 387 vs->network_error_count = 0; … … 355 396 struct hdhomerun_video_stats_t stats; 356 397 hdhomerun_video_get_stats(vs, &stats); 357 398 358 hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%l d net=%ld te=%ld miss=%ld drop=%ld\n",359 stats.packet_count,stats.network_error_count,360 stats.transport_error_count,stats.sequence_error_count,361 stats.overflow_error_count399 hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%lu net=%lu te=%lu miss=%lu drop=%lu\n", 400 (unsigned long)stats.packet_count, (unsigned long)stats.network_error_count, 401 (unsigned long)stats.transport_error_count, (unsigned long)stats.sequence_error_count, 402 (unsigned long)stats.overflow_error_count 362 403 ); 363 404 } 364 405 -
hdhomerun_os_posix.h
1 1 /* 2 2 * hdhomerun_os_posix.h 3 3 * 4 * Copyright © 2006-2008Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 38 38 #include <unistd.h> 39 39 #include <errno.h> 40 40 #include <fcntl.h> 41 #include <signal.h> 41 42 #include <sys/types.h> 42 43 #include <sys/socket.h> 43 44 #include <sys/time.h> 44 45 #include <sys/timeb.h> 45 46 #include <sys/wait.h> 46 #include <sys/signal.h>47 47 #include <netinet/in.h> 48 48 #include <arpa/inet.h> 49 49 #include <netdb.h> 50 50 #include <pthread.h> 51 51 52 52 typedef int bool_t; 53 typedef void (*sig_t)(int); 53 54 54 55 #define LIBTYPE 55 #define sock_getlasterror errno56 #define sock_getlasterror_socktimeout (errno == EAGAIN)57 56 #define console_vprintf vprintf 58 57 #define console_printf printf 59 58 #define THREAD_FUNC_PREFIX void * 60 59 61 static inline uint64_t getcurrenttime(void) 62 { 63 struct timeval t; 64 gettimeofday(&t, NULL); 65 return ((uint64_t)t.tv_sec * 1000) + (t.tv_usec / 1000); 66 } 60 #ifdef __cplusplus 61 extern "C" { 62 #endif 67 63 68 static inline int msleep(unsigned int ms) 69 { 70 uint64_t stop_time = getcurrenttime() + ms;64 extern LIBTYPE uint64_t getcurrenttime(void); 65 extern LIBTYPE void msleep_approx(uint64_t ms); 66 extern LIBTYPE void msleep_minimum(uint64_t ms); 71 67 72 while (1) { 73 uint64_t current_time = getcurrenttime(); 74 if (current_time >= stop_time) { 75 return 0; 76 } 77 78 uint64_t delay_s = (stop_time - current_time) / 1000; 79 if (delay_s > 0) { 80 sleep((unsigned int)delay_s); 81 continue; 82 } 83 84 uint64_t delay_us = (stop_time - current_time) * 1000; 85 usleep((unsigned int)delay_us); 86 } 68 #ifdef __cplusplus 87 69 } 88 89 static inline int setsocktimeout(int s, int level, int optname, uint64_t timeout) 90 { 91 struct timeval t; 92 t.tv_sec = timeout / 1000; 93 t.tv_usec = (timeout % 1000) * 1000; 94 return setsockopt(s, level, optname, (char *)&t, sizeof(t)); 95 } 70 #endif -
hdhomerun_sock_windows.c
1 /* 2 * hdhomerun_sock_windows.c 3 * 4 * Copyright © 2010 Silicondust USA Inc. <www.silicondust.com>. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 3 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * As a special exception to the GNU Lesser General Public License, 20 * you may link, statically or dynamically, an application with a 21 * publicly distributed version of the Library to produce an 22 * executable file containing portions of the Library, and 23 * distribute that executable file under terms of your choice, 24 * without any of the additional requirements listed in clause 4 of 25 * the GNU Lesser General Public License. 26 * 27 * By "a publicly distributed version of the Library", we mean 28 * either the unmodified Library as distributed by Silicondust, or a 29 * modified version of the Library that is distributed under the 30 * conditions defined in the GNU Lesser General Public License. 31 */ 32 33 /* 34 * Implementation notes: 35 * 36 * API specifies timeout for each operation (or zero for non-blocking). 37 * 38 * It is not possible to rely on the OS socket timeout as this will fail to 39 * detect the command-response situation where data is sent successfully and 40 * the other end chooses not to send a response (other than the TCP ack). 41 * 42 * Windows supports select() however native WSA events are used to: 43 * - avoid problems with socket numbers above 1024. 44 * - wait without allowing other events handlers to run (important for use 45 * with win7 WMC). 46 */ 47 48 #include "hdhomerun.h" 49 50 hdhomerun_sock_t hdhomerun_sock_create_udp(void) 51 { 52 /* Create socket. */ 53 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_DGRAM, 0); 54 if (sock == -1) { 55 return HDHOMERUN_SOCK_INVALID; 56 } 57 58 /* Set non-blocking */ 59 unsigned long mode = 1; 60 if (ioctlsocket(sock, FIONBIO, &mode) != 0) { 61 closesocket(sock); 62 return HDHOMERUN_SOCK_INVALID; 63 } 64 65 /* Allow broadcast. */ 66 int sock_opt = 1; 67 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt)); 68 69 /* Success. */ 70 return sock; 71 } 72 73 hdhomerun_sock_t hdhomerun_sock_create_tcp(void) 74 { 75 /* Create socket. */ 76 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_STREAM, 0); 77 if (sock == -1) { 78 return HDHOMERUN_SOCK_INVALID; 79 } 80 81 /* Set non-blocking */ 82 unsigned long mode = 1; 83 if (ioctlsocket(sock, FIONBIO, &mode) != 0) { 84 closesocket(sock); 85 return HDHOMERUN_SOCK_INVALID; 86 } 87 88 /* Success. */ 89 return sock; 90 } 91 92 void hdhomerun_sock_destroy(hdhomerun_sock_t sock) 93 { 94 closesocket(sock); 95 } 96 97 int hdhomerun_sock_getlasterror(void) 98 { 99 return WSAGetLastError(); 100 } 101 102 uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock) 103 { 104 struct sockaddr_in sock_addr; 105 int sockaddr_size = sizeof(sock_addr); 106 107 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 108 return 0; 109 } 110 111 return ntohl(sock_addr.sin_addr.s_addr); 112 } 113 114 uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock) 115 { 116 struct sockaddr_in sock_addr; 117 int sockaddr_size = sizeof(sock_addr); 118 119 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 120 return 0; 121 } 122 123 return ntohs(sock_addr.sin_port); 124 } 125 126 uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock) 127 { 128 struct sockaddr_in sock_addr; 129 int sockaddr_size = sizeof(sock_addr); 130 131 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 132 return 0; 133 } 134 135 return ntohl(sock_addr.sin_addr.s_addr); 136 } 137 138 uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name) 139 { 140 struct addrinfo hints; 141 memset(&hints, 0, sizeof(hints)); 142 hints.ai_family = AF_INET; 143 hints.ai_socktype = SOCK_STREAM; 144 hints.ai_protocol = IPPROTO_TCP; 145 146 struct addrinfo *sock_info; 147 if (getaddrinfo(name, "", &hints, &sock_info) != 0) { 148 return 0; 149 } 150 151 struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr; 152 uint32_t addr = ntohl(sock_addr->sin_addr.s_addr); 153 154 freeaddrinfo(sock_info); 155 return addr; 156 } 157 158 bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port) 159 { 160 struct sockaddr_in sock_addr; 161 memset(&sock_addr, 0, sizeof(sock_addr)); 162 sock_addr.sin_family = AF_INET; 163 sock_addr.sin_addr.s_addr = htonl(local_addr); 164 sock_addr.sin_port = htons(local_port); 165 166 if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 167 return FALSE; 168 } 169 170 return TRUE; 171 } 172 173 bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout) 174 { 175 WSAEVENT wsa_event = WSACreateEvent(); 176 if (wsa_event == WSA_INVALID_EVENT) { 177 return FALSE; 178 } 179 180 if (WSAEventSelect(sock, wsa_event, FD_CONNECT) == SOCKET_ERROR) { 181 WSACloseEvent(wsa_event); 182 return FALSE; 183 } 184 185 /* Connect (non-blocking). */ 186 struct sockaddr_in sock_addr; 187 memset(&sock_addr, 0, sizeof(sock_addr)); 188 sock_addr.sin_family = AF_INET; 189 sock_addr.sin_addr.s_addr = htonl(remote_addr); 190 sock_addr.sin_port = htons(remote_port); 191 192 if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 193 if (WSAGetLastError() != WSAEWOULDBLOCK) { 194 WSACloseEvent(wsa_event); 195 return FALSE; 196 } 197 } 198 199 /* Wait for connect to complete (both success and failure will signal). */ 200 DWORD ret = WaitForSingleObjectEx(wsa_event, (DWORD)timeout, FALSE); 201 WSACloseEvent(wsa_event); 202 203 if (ret != WAIT_OBJECT_0) { 204 return FALSE; 205 } 206 207 /* Detect success/failure. */ 208 int sockaddr_size = sizeof(sock_addr); 209 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 210 return FALSE; 211 } 212 213 return TRUE; 214 } 215 216 static bool_t hdhomerun_sock_wait_for_event(hdhomerun_sock_t sock, long event_type, uint64_t stop_time) 217 { 218 uint64_t current_time = getcurrenttime(); 219 if (current_time >= stop_time) { 220 return FALSE; 221 } 222 223 WSAEVENT wsa_event = WSACreateEvent(); 224 if (wsa_event == WSA_INVALID_EVENT) { 225 return FALSE; 226 } 227 228 if (WSAEventSelect(sock, wsa_event, event_type) == SOCKET_ERROR) { 229 WSACloseEvent(wsa_event); 230 return FALSE; 231 } 232 233 DWORD ret = WaitForSingleObjectEx(wsa_event, (DWORD)(stop_time - current_time), FALSE); 234 WSACloseEvent(wsa_event); 235 236 if (ret != WAIT_OBJECT_0) { 237 return FALSE; 238 } 239 240 return TRUE; 241 } 242 243 bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout) 244 { 245 uint64_t stop_time = getcurrenttime() + timeout; 246 const uint8_t *ptr = (uint8_t *)data; 247 248 while (1) { 249 int ret = send(sock, (char *)ptr, (int)length, 0); 250 if (ret >= (int)length) { 251 return TRUE; 252 } 253 254 if (ret > 0) { 255 ptr += ret; 256 length -= ret; 257 } 258 259 if (WSAGetLastError() != WSAEWOULDBLOCK) { 260 return FALSE; 261 } 262 263 if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) { 264 return FALSE; 265 } 266 } 267 } 268 269 bool_t hdhomerun_sock_sendto(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout) 270 { 271 uint64_t stop_time = getcurrenttime() + timeout; 272 const uint8_t *ptr = (uint8_t *)data; 273 274 while (1) { 275 struct sockaddr_in sock_addr; 276 memset(&sock_addr, 0, sizeof(sock_addr)); 277 sock_addr.sin_family = AF_INET; 278 sock_addr.sin_addr.s_addr = htonl(remote_addr); 279 sock_addr.sin_port = htons(remote_port); 280 281 int ret = sendto(sock, (char *)ptr, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); 282 if (ret >= (int)length) { 283 return TRUE; 284 } 285 286 if (ret > 0) { 287 ptr += ret; 288 length -= ret; 289 } 290 291 if (WSAGetLastError() != WSAEWOULDBLOCK) { 292 return FALSE; 293 } 294 295 if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) { 296 return FALSE; 297 } 298 } 299 } 300 301 bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout) 302 { 303 uint64_t stop_time = getcurrenttime() + timeout; 304 305 while (1) { 306 int ret = recv(sock, (char *)data, (int)(*length), 0); 307 if (ret > 0) { 308 *length = ret; 309 return TRUE; 310 } 311 312 if (WSAGetLastError() != WSAEWOULDBLOCK) { 313 return FALSE; 314 } 315 316 if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) { 317 return FALSE; 318 } 319 } 320 } 321 322 bool_t hdhomerun_sock_recvfrom(hdhomerun_sock_t sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout) 323 { 324 uint64_t stop_time = getcurrenttime() + timeout; 325 326 while (1) { 327 struct sockaddr_in sock_addr; 328 memset(&sock_addr, 0, sizeof(sock_addr)); 329 int sockaddr_size = sizeof(sock_addr); 330 331 int ret = recvfrom(sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size); 332 if (ret > 0) { 333 *remote_addr = ntohl(sock_addr.sin_addr.s_addr); 334 *remote_port = ntohs(sock_addr.sin_port); 335 *length = ret; 336 return TRUE; 337 } 338 339 if (WSAGetLastError() != WSAEWOULDBLOCK) { 340 return FALSE; 341 } 342 343 if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) { 344 return FALSE; 345 } 346 } 347 } -
hdhomerun_video.h
Property changes on: hdhomerun_sock_windows.c ___________________________________________________________________ Added: svn:executable + *
1 1 /* 2 2 * hdhomerun_video.h 3 3 * 4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 71 71 extern LIBTYPE uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs); 72 72 73 73 /* 74 * Join/leave multicast group. 75 */ 76 extern LIBTYPE int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip); 77 extern LIBTYPE int hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs); 78 79 /* 74 80 * Read data from buffer. 75 81 * 76 82 * size_t max_size: The maximum amount of data to be returned. … … 100 106 extern LIBTYPE void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs); 101 107 extern LIBTYPE void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomerun_video_stats_t *stats); 102 108 109 /* 110 * Internal use only. 111 */ 112 extern LIBTYPE hdhomerun_sock_t hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs); 113 103 114 #ifdef __cplusplus 104 115 } 105 116 #endif -
hdhomerun_channelscan.c
1 1 /* 2 2 * hdhomerun_channelscan.c 3 3 * 4 * Copyright © 2007-2008Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2007-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 99 99 return 1; 100 100 } 101 101 102 msleep (250);102 msleep_approx(250); 103 103 } 104 104 } 105 105 … … 303 303 break; 304 304 } 305 305 306 msleep (250);306 msleep_approx(250); 307 307 } 308 308 309 309 /* Lock => skip overlapping channels. */ -
hdhomerun_discover.c
1 1 /* 2 2 * hdhomerun_discover.c 3 3 * 4 * Copyright © 2006-2007Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 44 44 #endif 45 45 #endif 46 46 47 #include <sys/param.h> // Defines BSD on FreeBSD and Mac OS X48 #if defined(__linux__) || defined(__APPLE__) || defined(BSD)49 # include <ifaddrs.h>50 # define USE_IFADDRS 151 # include <sys/select.h>52 #endif53 54 47 #define HDHOMERUN_DISOCVER_MAX_SOCK_COUNT 16 55 48 56 49 struct hdhomerun_discover_sock_t { 57 int sock; 50 hdhomerun_sock_t sock; 51 bool_t detected; 58 52 uint32_t local_ip; 59 53 uint32_t subnet_mask; 60 54 }; … … 66 60 struct hdhomerun_pkt_t rx_pkt; 67 61 }; 68 62 69 static bool_t hdhomerun_discover_sock_ create(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)63 static bool_t hdhomerun_discover_sock_add(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask) 70 64 { 65 unsigned int i; 66 for (i = 1; i < ds->sock_count; i++) { 67 struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; 68 69 if ((dss->local_ip == local_ip) && (dss->subnet_mask == subnet_mask)) { 70 dss->detected = TRUE; 71 return TRUE; 72 } 73 } 74 71 75 if (ds->sock_count >= HDHOMERUN_DISOCVER_MAX_SOCK_COUNT) { 72 76 return FALSE; 73 77 } 74 78 75 79 /* Create socket. */ 76 int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);77 if (sock == -1) {80 hdhomerun_sock_t sock = hdhomerun_sock_create_udp(); 81 if (sock == HDHOMERUN_SOCK_INVALID) { 78 82 return FALSE; 79 83 } 80 84 81 /* Set timeouts. */82 setsocktimeout(sock, SOL_SOCKET, SO_SNDTIMEO, 1000);83 setsocktimeout(sock, SOL_SOCKET, SO_RCVTIMEO, 1000);84 85 /* Allow broadcast. */86 int sock_opt = 1;87 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));88 89 85 /* Bind socket. */ 90 struct sockaddr_in sock_addr; 91 memset(&sock_addr, 0, sizeof(sock_addr)); 92 sock_addr.sin_family = AF_INET; 93 sock_addr.sin_addr.s_addr = htonl(local_ip); 94 sock_addr.sin_port = htons(0); 95 if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 96 close(sock); 86 if (!hdhomerun_sock_bind(sock, local_ip, 0)) { 87 hdhomerun_sock_destroy(sock); 97 88 return FALSE; 98 89 } 99 90 100 91 /* Write sock entry. */ 101 92 struct hdhomerun_discover_sock_t *dss = &ds->socks[ds->sock_count++]; 102 93 dss->sock = sock; 94 dss->detected = TRUE; 103 95 dss->local_ip = local_ip; 104 96 dss->subnet_mask = subnet_mask; 105 97 106 98 return TRUE; 107 99 } 108 100 101 struct hdhomerun_discover_t *hdhomerun_discover_create(void) 102 { 103 struct hdhomerun_discover_t *ds = (struct hdhomerun_discover_t *)calloc(1, sizeof(struct hdhomerun_discover_t)); 104 if (!ds) { 105 return NULL; 106 } 107 108 /* Create a routable socket (always first entry). */ 109 if (!hdhomerun_discover_sock_add(ds, 0, 0)) { 110 free(ds); 111 return NULL; 112 } 113 114 /* Success. */ 115 return ds; 116 } 117 118 void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds) 119 { 120 unsigned int i; 121 for (i = 0; i < ds->sock_count; i++) { 122 struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; 123 hdhomerun_sock_destroy(dss->sock); 124 } 125 126 free(ds); 127 } 128 109 129 #if defined(USE_IPHLPAPI) 110 static void hdhomerun_discover_sock_detect (struct hdhomerun_discover_t *ds)130 static void hdhomerun_discover_sock_detect_internal(struct hdhomerun_discover_t *ds) 111 131 { 112 132 PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO)); 113 133 ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); … … 138 158 continue; 139 159 } 140 160 141 hdhomerun_discover_sock_ create(ds, local_ip, mask);161 hdhomerun_discover_sock_add(ds, local_ip, mask); 142 162 pIPAddr = pIPAddr->Next; 143 163 } 144 164 … … 150 170 151 171 #else 152 172 153 static void hdhomerun_discover_sock_detect (struct hdhomerun_discover_t *ds)173 static void hdhomerun_discover_sock_detect_internal(struct hdhomerun_discover_t *ds) 154 174 { 155 int fd = socket(AF_INET, SOCK_DGRAM, 0); 156 if (fd == -1) { 157 return; 158 } 175 int sock = ds->socks[0].sock; 159 176 160 177 struct ifconf ifc; 161 178 uint8_t buf[8192]; … … 164 181 165 182 memset(buf, 0, sizeof(buf)); 166 183 167 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { 168 close(fd); 184 if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) { 169 185 return; 170 186 } 171 187 … … 176 192 struct ifreq *ifr = (struct ifreq *)ptr; 177 193 ptr += _SIZEOF_ADDR_IFREQ(*ifr); 178 194 179 if (ioctl( fd, SIOCGIFADDR, ifr) != 0) {195 if (ioctl(sock, SIOCGIFADDR, ifr) != 0) { 180 196 continue; 181 197 } 182 198 struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr); … … 185 201 continue; 186 202 } 187 203 188 if (ioctl( fd, SIOCGIFNETMASK, ifr) != 0) {204 if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) { 189 205 continue; 190 206 } 191 207 struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr); 192 208 uint32_t mask = ntohl(mask_in->sin_addr.s_addr); 193 209 194 hdhomerun_discover_sock_ create(ds, local_ip, mask);210 hdhomerun_discover_sock_add(ds, local_ip, mask); 195 211 } 196 197 close(fd);198 212 } 199 213 #endif 200 214 201 static struct hdhomerun_discover_t *hdhomerun_discover_create(void)215 static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds) 202 216 { 203 struct hdhomerun_discover_t *ds = (struct hdhomerun_discover_t *)calloc(1, sizeof(struct hdhomerun_discover_t)); 204 if (!ds) { 205 return NULL; 217 unsigned int i; 218 for (i = 1; i < ds->sock_count; i++) { 219 struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; 220 dss->detected = FALSE; 206 221 } 207 222 208 /* Create a routable socket. */ 209 if (!hdhomerun_discover_sock_create(ds, 0, 0)) { 210 free(ds); 211 return NULL; 212 } 223 hdhomerun_discover_sock_detect_internal(ds); 213 224 214 /* Detect & create local sockets. */ 215 hdhomerun_discover_sock_detect(ds); 216 217 /* Success. */ 218 return ds; 219 } 220 221 static void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds) 222 { 223 unsigned int i; 224 for (i = 0; i < ds->sock_count; i++) { 225 struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; 226 close(dss->sock); 225 struct hdhomerun_discover_sock_t *src = &ds->socks[1]; 226 struct hdhomerun_discover_sock_t *dst = &ds->socks[1]; 227 unsigned int count = 1; 228 for (i = 1; i < ds->sock_count; i++) { 229 if (!src->detected) { 230 hdhomerun_sock_destroy(src->sock); 231 src++; 232 continue; 233 } 234 if (dst != src) { 235 *dst = *src; 236 } 237 src++; 238 dst++; 239 count++; 227 240 } 228 241 229 free(ds);242 ds->sock_count = count; 230 243 } 231 244 232 245 static bool_t hdhomerun_discover_send_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, uint32_t target_ip, uint32_t device_type, uint32_t device_id) … … 242 255 hdhomerun_pkt_write_u32(tx_pkt, device_id); 243 256 hdhomerun_pkt_seal_frame(tx_pkt, HDHOMERUN_TYPE_DISCOVER_REQ); 244 257 245 struct sockaddr_in sock_addr; 246 memset(&sock_addr, 0, sizeof(sock_addr)); 247 sock_addr.sin_family = AF_INET; 248 sock_addr.sin_addr.s_addr = htonl(target_ip); 249 sock_addr.sin_port = htons(HDHOMERUN_DISCOVER_UDP_PORT); 250 251 int length = (int)(tx_pkt->end - tx_pkt->start); 252 if (sendto(dss->sock, (char *)tx_pkt->start, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != length) { 253 return FALSE; 254 } 255 256 return TRUE; 258 return hdhomerun_sock_sendto(dss->sock, target_ip, HDHOMERUN_DISCOVER_UDP_PORT, tx_pkt->start, tx_pkt->end - tx_pkt->start, 0); 257 259 } 258 260 259 261 static bool_t hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id) … … 313 315 314 316 static bool_t hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) 315 317 { 316 if (target_ip != 0) { 318 if (target_ip == 0) { 319 return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id); 320 } else { 317 321 return hdhomerun_discover_send_target_ip(ds, target_ip, device_type, device_id); 318 322 } 319 320 return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id);321 323 } 322 324 323 static int hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result)325 static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result) 324 326 { 325 327 struct hdhomerun_pkt_t *rx_pkt = &ds->rx_pkt; 326 328 hdhomerun_pkt_reset(rx_pkt); 327 329 328 struct sockaddr_in sock_addr; 329 memset(&sock_addr, 0, sizeof(sock_addr)); 330 socklen_t sockaddr_size = sizeof(sock_addr); 331 332 int rx_length = recvfrom(dss->sock, (char *)rx_pkt->end, (int)(rx_pkt->limit - rx_pkt->end), 0, (struct sockaddr *)&sock_addr, &sockaddr_size); 333 if (rx_length <= 0) { 334 /* Don't return error - windows machine on VPN can sometimes cause a sock error here but otherwise works. */ 335 return 0; 330 uint32_t remote_addr; 331 uint16_t remote_port; 332 size_t length = rx_pkt->limit - rx_pkt->end; 333 if (!hdhomerun_sock_recvfrom(dss->sock, &remote_addr, &remote_port, rx_pkt->end, &length, 0)) { 334 return FALSE; 336 335 } 337 rx_pkt->end += rx_length;338 336 337 rx_pkt->end += length; 338 339 339 uint16_t type; 340 340 if (hdhomerun_pkt_open_frame(rx_pkt, &type) <= 0) { 341 return 0;341 return FALSE; 342 342 } 343 343 if (type != HDHOMERUN_TYPE_DISCOVER_RPY) { 344 return 0;344 return FALSE; 345 345 } 346 346 347 result->ip_addr = ntohl(sock_addr.sin_addr.s_addr);347 result->ip_addr = remote_addr; 348 348 result->device_type = 0; 349 349 result->device_id = 0; 350 350 … … 378 378 rx_pkt->pos = next; 379 379 } 380 380 381 return 1;381 return TRUE; 382 382 } 383 383 384 static int hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result)384 static bool_t hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result) 385 385 { 386 struct timeval t;387 t.tv_sec = 0;388 t.tv_usec = 250000;389 390 fd_set readfds;391 FD_ZERO(&readfds);392 int max_sock = -1;393 394 386 unsigned int i; 395 387 for (i = 0; i < ds->sock_count; i++) { 396 388 struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; 397 FD_SET(dss->sock, &readfds);398 if (dss->sock > max_sock) {399 max_sock = dss->sock;400 }401 }402 389 403 if (select(max_sock+1, &readfds, NULL, NULL, &t) < 0) { 404 return -1; 405 } 406 407 for (i = 0; i < ds->sock_count; i++) { 408 struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; 409 if (!FD_ISSET(dss->sock, &readfds)) { 410 continue; 390 if (hdhomerun_discover_recv_internal(ds, dss, result)) { 391 return TRUE; 411 392 } 412 413 if (hdhomerun_discover_recv_internal(ds, dss, result) <= 0) {414 continue;415 }416 417 return 1;418 393 } 419 394 420 return 0;395 return FALSE; 421 396 } 422 397 423 static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struct hdhomerun_discover_device_t result_list[], int count, uint32_t ip_addr)398 static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struct hdhomerun_discover_device_t result_list[], int count, struct hdhomerun_discover_device_t *lookup) 424 399 { 425 400 int index; 426 401 for (index = 0; index < count; index++) { 427 struct hdhomerun_discover_device_t * result= &result_list[index];428 if ( result->ip_addr == ip_addr) {429 return result;402 struct hdhomerun_discover_device_t *entry = &result_list[index]; 403 if (memcmp(lookup, entry, sizeof(struct hdhomerun_discover_device_t)) == 0) { 404 return entry; 430 405 } 431 406 } 432 407 433 408 return NULL; 434 409 } 435 410 436 static int hdhomerun_discover_find_devices_internal(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count)411 int hdhomerun_discover_find_devices(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count) 437 412 { 413 hdhomerun_discover_sock_detect(ds); 414 438 415 int count = 0; 439 416 int attempt; 440 417 for (attempt = 0; attempt < 2; attempt++) { … … 443 420 } 444 421 445 422 uint64_t timeout = getcurrenttime() + 200; 446 while ( getcurrenttime() < timeout) {423 while (1) { 447 424 struct hdhomerun_discover_device_t *result = &result_list[count]; 448 425 449 i nt ret = hdhomerun_discover_recv(ds, result);450 if (ret < 0) {451 return -1;452 }453 if (ret == 0) {426 if (!hdhomerun_discover_recv(ds, result)) { 427 if (getcurrenttime() >= timeout) { 428 break; 429 } 430 msleep_approx(10); 454 431 continue; 455 432 } 456 433 … … 467 444 } 468 445 469 446 /* Ensure not already in list. */ 470 if (hdhomerun_discover_find_in_list(result_list, count, result ->ip_addr)) {447 if (hdhomerun_discover_find_in_list(result_list, count, result)) { 471 448 continue; 472 449 } 473 450 … … 484 461 485 462 int hdhomerun_discover_find_devices_custom(uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count) 486 463 { 464 if (hdhomerun_discover_is_ip_multicast(target_ip)) { 465 return 0; 466 } 467 487 468 struct hdhomerun_discover_t *ds = hdhomerun_discover_create(); 488 469 if (!ds) { 489 470 return -1; 490 471 } 491 472 492 int ret = hdhomerun_discover_find_devices _internal(ds, target_ip, device_type, device_id, result_list, max_count);473 int ret = hdhomerun_discover_find_devices(ds, target_ip, device_type, device_id, result_list, max_count); 493 474 494 475 hdhomerun_discover_destroy(ds); 495 476 return ret; … … 513 494 return (checksum == 0); 514 495 } 515 496 497 bool_t hdhomerun_discover_is_ip_multicast(uint32_t ip_addr) 498 { 499 return (ip_addr >= 0xE0000000) && (ip_addr < 0xF0000000); 500 } -
hdhomerun_dhcp.c
1 /*2 * hdhomerun_dhcp.c3 *4 * Copyright © 2006-2007 Silicondust USA Inc. <www.silicondust.com>.5 *6 * This library is free software; you can redistribute it and/or7 * modify it under the terms of the GNU Lesser General Public8 * License as published by the Free Software Foundation; either9 * version 3 of the License, or (at your option) any later version.10 *11 * This library is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU14 * Lesser General Public License for more details.15 *16 * You should have received a copy of the GNU Lesser General Public17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.18 *19 * As a special exception to the GNU Lesser General Public License,20 * you may link, statically or dynamically, an application with a21 * publicly distributed version of the Library to produce an22 * executable file containing portions of the Library, and23 * distribute that executable file under terms of your choice,24 * without any of the additional requirements listed in clause 4 of25 * the GNU Lesser General Public License.26 *27 * By "a publicly distributed version of the Library", we mean28 * either the unmodified Library as distributed by Silicondust, or a29 * modified version of the Library that is distributed under the30 * conditions defined in the GNU Lesser General Public License.31 */32 33 #include "hdhomerun.h"34 #include "hdhomerun_dhcp.h"35 36 struct dhcp_hdr_t {37 uint8_t bootp_message_type;38 uint8_t hardware_type;39 uint8_t hardware_address_length;40 uint8_t hops;41 uint32_t transaction_id;42 uint16_t seconds_elapsed;43 uint16_t bootp_flags;44 uint32_t client_ip;45 uint32_t your_ip;46 uint32_t next_server_ip;47 uint32_t relay_agent_ip;48 uint8_t client_mac[16];49 uint8_t server_host_name[64];50 uint8_t boot_file_name[128];51 uint32_t magic_cookie;52 };53 54 struct hdhomerun_dhcp_t {55 int sock;56 uint32_t local_address;57 pthread_t thread;58 volatile bool_t terminate;59 };60 61 static THREAD_FUNC_PREFIX hdhomerun_dhcp_thread_execute(void *arg);62 63 struct hdhomerun_dhcp_t *hdhomerun_dhcp_create(uint32_t bind_address)64 {65 if (bind_address != 0) {66 if ((bind_address & 0xFFFF0000) != 0xA9FE0000) {67 return NULL;68 }69 }70 71 /* Create socket. */72 int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);73 if (sock == -1) {74 return NULL;75 }76 77 /* Set timeout. */78 setsocktimeout(sock, SOL_SOCKET, SO_RCVTIMEO, 1000);79 80 /* Allow broadcast. */81 int sock_opt = 1;82 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));83 84 /* Allow reuse. */85 sock_opt = 1;86 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt));87 88 /* Bind socket. */89 struct sockaddr_in sock_addr;90 memset(&sock_addr, 0, sizeof(sock_addr));91 sock_addr.sin_family = AF_INET;92 sock_addr.sin_addr.s_addr = htonl(bind_address);93 sock_addr.sin_port = htons(67);94 if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {95 close(sock);96 return NULL;97 }98 99 /* Allocate object. */100 struct hdhomerun_dhcp_t *dhcp = (struct hdhomerun_dhcp_t *)calloc(1, sizeof(struct hdhomerun_dhcp_t));101 if (!dhcp) {102 close(sock);103 return NULL;104 }105 106 dhcp->sock = sock;107 108 if (bind_address != 0) {109 dhcp->local_address = bind_address;110 } else {111 dhcp->local_address = 0xA9FEFFFF;112 }113 114 /* Spawn thread. */115 if (pthread_create(&dhcp->thread, NULL, &hdhomerun_dhcp_thread_execute, dhcp) != 0) {116 close(sock);117 free(dhcp);118 return NULL;119 }120 121 /* Success. */122 return dhcp;123 }124 125 void hdhomerun_dhcp_destroy(struct hdhomerun_dhcp_t *dhcp)126 {127 dhcp->terminate = TRUE;128 pthread_join(dhcp->thread, NULL);129 130 close(dhcp->sock);131 free(dhcp);132 }133 134 static void hdhomerun_dhcp_send(struct hdhomerun_dhcp_t *dhcp, uint8_t message_type, struct hdhomerun_pkt_t *pkt)135 {136 pkt->pos = pkt->start;137 struct dhcp_hdr_t *hdr = (struct dhcp_hdr_t *)pkt->pos;138 pkt->pos += sizeof(struct dhcp_hdr_t);139 pkt->end = pkt->pos;140 141 uint32_t remote_addr = 0xA9FE0000;142 remote_addr |= (uint32_t)hdr->client_mac[4] << 8;143 remote_addr |= (uint32_t)hdr->client_mac[5] << 0;144 if ((remote_addr == 0xA9FE0000) || (remote_addr == 0xA9FEFFFF)) {145 remote_addr = 0xA9FE8080;146 }147 148 hdr->bootp_message_type = 0x02;149 hdr->your_ip = htonl(remote_addr);150 hdr->next_server_ip = htonl(0x00000000);151 152 hdhomerun_pkt_write_u8(pkt, 53);153 hdhomerun_pkt_write_u8(pkt, 1);154 hdhomerun_pkt_write_u8(pkt, message_type);155 156 hdhomerun_pkt_write_u8(pkt, 54);157 hdhomerun_pkt_write_u8(pkt, 4);158 hdhomerun_pkt_write_u32(pkt, dhcp->local_address);159 160 hdhomerun_pkt_write_u8(pkt, 51);161 hdhomerun_pkt_write_u8(pkt, 4);162 hdhomerun_pkt_write_u32(pkt, 7*24*60*60);163 164 hdhomerun_pkt_write_u8(pkt, 1);165 hdhomerun_pkt_write_u8(pkt, 4);166 hdhomerun_pkt_write_u32(pkt, 0xFFFF0000);167 168 hdhomerun_pkt_write_u8(pkt, 0xFF);169 170 while (pkt->pos < pkt->start + 300) {171 hdhomerun_pkt_write_u8(pkt, 0x00);172 }173 174 struct sockaddr_in sock_addr;175 memset(&sock_addr, 0, sizeof(sock_addr));176 sock_addr.sin_family = AF_INET;177 sock_addr.sin_addr.s_addr = htonl(0xFFFFFFFF);178 sock_addr.sin_port = htons(68);179 180 sendto(dhcp->sock, (char *)pkt->start, (int)(pkt->end - pkt->start), 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));181 }182 183 static void hdhomerun_dhcp_recv(struct hdhomerun_dhcp_t *dhcp, struct hdhomerun_pkt_t *pkt)184 {185 pkt->pos = pkt->start;186 struct dhcp_hdr_t *hdr = (struct dhcp_hdr_t *)pkt->pos;187 pkt->pos += sizeof(struct dhcp_hdr_t);188 if (pkt->pos > pkt->end) {189 return;190 }191 192 if (ntohl(hdr->magic_cookie) != 0x63825363) {193 return;194 }195 196 static uint8_t vendor[3] = {0x00, 0x18, 0xDD};197 if (memcmp(hdr->client_mac, vendor, 3) != 0) {198 return;199 }200 201 if (pkt->pos + 3 > pkt->end) {202 return;203 }204 if (hdhomerun_pkt_read_u8(pkt) != 53) {205 return;206 }207 if (hdhomerun_pkt_read_u8(pkt) != 1) {208 return;209 }210 uint8_t message_type_val = hdhomerun_pkt_read_u8(pkt);211 212 switch (message_type_val) {213 case 0x01:214 hdhomerun_dhcp_send(dhcp, 0x02, pkt);215 break;216 case 0x03:217 hdhomerun_dhcp_send(dhcp, 0x05, pkt);218 break;219 default:220 return;221 }222 }223 224 static THREAD_FUNC_PREFIX hdhomerun_dhcp_thread_execute(void *arg)225 {226 struct hdhomerun_dhcp_t *dhcp = (struct hdhomerun_dhcp_t *)arg;227 struct hdhomerun_pkt_t pkt_inst;228 229 while (1) {230 if (dhcp->terminate) {231 return NULL;232 }233 234 struct hdhomerun_pkt_t *pkt = &pkt_inst;235 hdhomerun_pkt_reset(pkt);236 237 int rx_length = recv(dhcp->sock, (char *)pkt->end, (int)(pkt->limit - pkt->end), 0);238 if (rx_length <= 0) {239 if (!sock_getlasterror_socktimeout) {240 #if defined(__WINDOWS__)241 msleep(1000);242 #else243 sleep(1);244 #endif245 }246 continue;247 }248 pkt->end += rx_length;249 250 hdhomerun_dhcp_recv(dhcp, pkt);251 }252 } -
hdhomerun_channelscan.h
1 1 /* 2 2 * hdhomerun_channelscan.h 3 3 * 4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public -
hdhomerun_discover.h
1 1 /* 2 2 * hdhomerun_discover.h 3 3 * 4 * Copyright © 2006-2007 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2007 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 44 44 * 45 45 * The device information is stored in caller-supplied array of hdhomerun_discover_device_t vars. 46 46 * Multiple attempts are made to find devices. 47 * Execution time is 1 second.47 * Execution time is typically 400ms if max_count is not reached. 48 48 * 49 * Set target_ip to zero to auto-detect IP address. 49 * Set target_ip to zero to auto-detect the IP address. 50 * Set device_type to HDHOMERUN_DEVICE_TYPE_TUNER to detect HDHomeRun tuner devices. 51 * Set device_id to HDHOMERUN_DEVICE_ID_WILDCARD to detect all device ids. 50 52 * 51 53 * Returns the number of devices found. 52 54 * Retruns -1 on error. … … 54 56 extern LIBTYPE int hdhomerun_discover_find_devices_custom(uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count); 55 57 56 58 /* 59 * Optional: persistent discover instance available for discover polling use. 60 */ 61 extern LIBTYPE struct hdhomerun_discover_t *hdhomerun_discover_create(void); 62 extern LIBTYPE void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds); 63 extern LIBTYPE int hdhomerun_discover_find_devices(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count); 64 65 /* 57 66 * Verify that the device ID given is valid. 58 67 * 59 68 * The device ID contains a self-check sequence that detects common user input errors including … … 64 73 */ 65 74 extern LIBTYPE bool_t hdhomerun_discover_validate_device_id(uint32_t device_id); 66 75 76 /* 77 * Detect if an IP address is multicast. 78 * 79 * Returns TRUE if multicast. 80 * Returns FALSE if zero, unicast, expermental, or broadcast. 81 */ 82 extern LIBTYPE bool_t hdhomerun_discover_is_ip_multicast(uint32_t ip_addr); 83 67 84 #ifdef __cplusplus 68 85 } 69 86 #endif -
hdhomerun_dhcp.h
1 /*2 * hdhomerun_dhcp.h3 *4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.5 *6 * This library is free software; you can redistribute it and/or7 * modify it under the terms of the GNU Lesser General Public8 * License as published by the Free Software Foundation; either9 * version 3 of the License, or (at your option) any later version.10 *11 * This library is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU14 * Lesser General Public License for more details.15 *16 * You should have received a copy of the GNU Lesser General Public17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.18 *19 * As a special exception to the GNU Lesser General Public License,20 * you may link, statically or dynamically, an application with a21 * publicly distributed version of the Library to produce an22 * executable file containing portions of the Library, and23 * distribute that executable file under terms of your choice,24 * without any of the additional requirements listed in clause 4 of25 * the GNU Lesser General Public License.26 *27 * By "a publicly distributed version of the Library", we mean28 * either the unmodified Library as distributed by Silicondust, or a29 * modified version of the Library that is distributed under the30 * conditions defined in the GNU Lesser General Public License.31 */32 33 #ifdef __cplusplus34 extern "C" {35 #endif36 37 struct hdhomerun_dhcp_t;38 39 extern LIBTYPE struct hdhomerun_dhcp_t *hdhomerun_dhcp_create(uint32_t bind_address);40 extern LIBTYPE void hdhomerun_dhcp_destroy(struct hdhomerun_dhcp_t *dhcp);41 42 #ifdef __cplusplus43 }44 #endif -
hdhomerun_os.h
1 1 /* 2 2 * hdhomerun_os.h 3 3 * 4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public -
hdhomerun_os_windows.c
1 /* 2 * hdhomerun_os_windows.c 3 * 4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 3 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * As a special exception to the GNU Lesser General Public License, 20 * you may link, statically or dynamically, an application with a 21 * publicly distributed version of the Library to produce an 22 * executable file containing portions of the Library, and 23 * distribute that executable file under terms of your choice, 24 * without any of the additional requirements listed in clause 4 of 25 * the GNU Lesser General Public License. 26 * 27 * By "a publicly distributed version of the Library", we mean 28 * either the unmodified Library as distributed by Silicondust, or a 29 * modified version of the Library that is distributed under the 30 * conditions defined in the GNU Lesser General Public License. 31 */ 32 33 #include "hdhomerun_os.h" 34 35 uint64_t getcurrenttime(void) 36 { 37 static pthread_mutex_t lock = INVALID_HANDLE_VALUE; 38 static uint64_t result = 0; 39 static uint32_t previous_time = 0; 40 41 /* Initialization is not thread safe. */ 42 if (lock == INVALID_HANDLE_VALUE) { 43 pthread_mutex_init(&lock, NULL); 44 } 45 46 pthread_mutex_lock(&lock); 47 48 uint32_t current_time = GetTickCount(); 49 50 if (current_time > previous_time) { 51 result += current_time - previous_time; 52 } 53 54 previous_time = current_time; 55 56 pthread_mutex_unlock(&lock); 57 return result; 58 } 59 60 void msleep_approx(uint64_t ms) 61 { 62 Sleep((DWORD)ms); 63 } 64 65 void msleep_minimum(uint64_t ms) 66 { 67 uint64_t stop_time = getcurrenttime() + ms; 68 69 while (1) { 70 uint64_t current_time = getcurrenttime(); 71 if (current_time >= stop_time) { 72 return; 73 } 74 75 msleep_approx(stop_time - current_time); 76 } 77 } 78 79 int pthread_create(pthread_t *tid, void *attr, LPTHREAD_START_ROUTINE start, void *arg) 80 { 81 *tid = CreateThread(NULL, 0, start, arg, 0, NULL); 82 if (!*tid) { 83 return (int)GetLastError(); 84 } 85 return 0; 86 } 87 88 int pthread_join(pthread_t tid, void **value_ptr) 89 { 90 while (1) { 91 DWORD ExitCode = 0; 92 if (!GetExitCodeThread(tid, &ExitCode)) { 93 return (int)GetLastError(); 94 } 95 if (ExitCode != STILL_ACTIVE) { 96 return 0; 97 } 98 } 99 } 100 101 void pthread_mutex_init(pthread_mutex_t *mutex, void *attr) 102 { 103 *mutex = CreateMutex(NULL, FALSE, NULL); 104 } 105 106 void pthread_mutex_lock(pthread_mutex_t *mutex) 107 { 108 WaitForSingleObject(*mutex, INFINITE); 109 } 110 111 void pthread_mutex_unlock(pthread_mutex_t *mutex) 112 { 113 ReleaseMutex(*mutex); 114 } 115 116 /* 117 * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing. 118 * Attempting to restore on exit fails to restore if the program is terminated by the user. 119 * Solution - set the output format each printf. 120 */ 121 void console_vprintf(const char *fmt, va_list ap) 122 { 123 UINT cp = GetConsoleOutputCP(); 124 SetConsoleOutputCP(CP_UTF8); 125 vprintf(fmt, ap); 126 SetConsoleOutputCP(cp); 127 } 128 129 void console_printf(const char *fmt, ...) 130 { 131 va_list ap; 132 va_start(ap, fmt); 133 console_vprintf(fmt, ap); 134 va_end(ap); 135 } -
hdhomerun_channels.c
Property changes on: hdhomerun_os_windows.c ___________________________________________________________________ Added: svn:executable + *
1 1 /* 2 2 * hdhomerun_channels.c 3 3 * 4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 55 55 }; 56 56 57 57 struct hdhomerun_channelmap_record_t { 58 const char *channelmap_prefix;59 58 const char *channelmap; 60 59 const struct hdhomerun_channelmap_range_t *range_list; 61 60 const char *channelmap_scan_group; … … 140 139 }; 141 140 142 141 static const struct hdhomerun_channelmap_record_t hdhomerun_channelmap_table[] = { 143 {"au", "au-bcast", hdhomerun_channelmap_range_au_bcast, "au-bcast", "AU"}, 144 {"au", "au-cable", hdhomerun_channelmap_range_au_cable, "au-cable", "AU"}, 145 {"eu", "eu-bcast", hdhomerun_channelmap_range_eu_bcast, "eu-bcast", "EU"}, 146 {"eu", "eu-cable", hdhomerun_channelmap_range_eu_cable, "eu-cable", "EU"}, 147 {"tw", "tw-bcast", hdhomerun_channelmap_range_us_bcast, "tw-bcast", "TW"}, 148 {"tw", "tw-cable", hdhomerun_channelmap_range_us_cable, "tw-cable", "TW"}, 149 {"us", "us-bcast", hdhomerun_channelmap_range_us_bcast, "us-bcast", "CA US"}, 150 {"us", "us-cable", hdhomerun_channelmap_range_us_cable, "us-cable us-hrc us-irc", "CA US"}, 151 {"us", "us-hrc", hdhomerun_channelmap_range_us_hrc , "us-cable us-hrc us-irc", "CA US"}, 152 {"us", "us-irc", hdhomerun_channelmap_range_us_irc, "us-cable us-hrc us-irc", "CA US"}, 153 {NULL, NULL, NULL, NULL, NULL} 142 {"au-bcast", hdhomerun_channelmap_range_au_bcast, "au-bcast", "AU"}, 143 {"au-cable", hdhomerun_channelmap_range_au_cable, "au-cable", "AU"}, 144 {"eu-bcast", hdhomerun_channelmap_range_eu_bcast, "eu-bcast", "EU PA"}, 145 {"eu-cable", hdhomerun_channelmap_range_eu_cable, "eu-cable", "EU"}, 146 {"tw-bcast", hdhomerun_channelmap_range_us_bcast, "tw-bcast", "TW"}, 147 {"tw-cable", hdhomerun_channelmap_range_us_cable, "tw-cable", "TW"}, 148 149 {"us-bcast", hdhomerun_channelmap_range_us_bcast, "us-bcast", "CA US"}, 150 {"us-cable", hdhomerun_channelmap_range_us_cable, "us-cable us-hrc us-irc", "CA PA US"}, 151 {"us-hrc", hdhomerun_channelmap_range_us_hrc , "us-cable us-hrc us-irc", "CA PA US"}, 152 {"us-irc", hdhomerun_channelmap_range_us_irc, "us-cable us-hrc us-irc", "CA PA US"}, 153 154 {NULL, NULL, NULL, NULL} 154 155 }; 155 156 156 const char *hdhomerun_channelmap_ convert_countrycode_to_channelmap_prefix(const char *countrycode)157 const char *hdhomerun_channelmap_get_channelmap_from_country_source(const char *countrycode, const char *source) 157 158 { 159 bool_t country_found = FALSE; 160 158 161 const struct hdhomerun_channelmap_record_t *record = hdhomerun_channelmap_table; 159 162 while (record->channelmap) { 160 if (strstr(record->countrycodes, countrycode)) { 161 return record->channelmap_prefix; 163 if (!strstr(record->countrycodes, countrycode)) { 164 record++; 165 continue; 162 166 } 167 168 if (strstr(record->channelmap, source)) { 169 return record->channelmap; 170 } 171 172 country_found = TRUE; 163 173 record++; 164 174 } 165 175 166 return "eu"; 176 if (!country_found) { 177 return hdhomerun_channelmap_get_channelmap_from_country_source("EU", source); 178 } 179 180 return NULL; 167 181 } 168 182 169 183 const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelmap) -
hdhomerun_pkt.c
1 1 /* 2 2 * hdhomerun_pkt.c 3 3 * 4 * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public -
hdhomerun_device.c
1 1 /* 2 2 * hdhomerun_device.c 3 3 * 4 * Copyright © 2006-2008Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 37 37 struct hdhomerun_video_sock_t *vs; 38 38 struct hdhomerun_debug_t *dbg; 39 39 struct hdhomerun_channelscan_t *scan; 40 uint32_t multicast_ip; 41 uint16_t multicast_port; 40 42 uint32_t device_id; 41 43 unsigned int tuner; 42 44 uint32_t lockkey; … … 44 46 char model[32]; 45 47 }; 46 48 47 static void hdhomerun_device_set_update(struct hdhomerun_device_t *hd)49 static int hdhomerun_device_set_device_normal(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip) 48 50 { 49 /* Clear cached information. */ 50 *hd->model = 0; 51 if (!hd->cs) { 52 hd->cs = hdhomerun_control_create(0, 0, hd->dbg); 53 if (!hd->cs) { 54 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: failed to create control object\n"); 55 return -1; 56 } 57 } 51 58 52 /* New name. */53 sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner);54 }55 56 void hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip)57 {58 59 hdhomerun_control_set_device(hd->cs, device_id, device_ip); 59 60 60 61 if ((device_id == 0) || (device_id == HDHOMERUN_DEVICE_ID_WILDCARD)) { 61 62 device_id = hdhomerun_control_get_device_id(hd->cs); 62 63 } 63 64 65 hd->multicast_ip = 0; 66 hd->multicast_port = 0; 64 67 hd->device_id = device_id; 65 hdhomerun_device_set_update(hd); 68 hd->tuner = 0; 69 hd->lockkey = 0; 70 71 sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner); 72 hd->model[0] = 0; /* clear cached model string */ 73 74 return 1; 66 75 } 67 76 68 void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)77 static int hdhomerun_device_set_device_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip) 69 78 { 79 if (hd->cs) { 80 hdhomerun_control_destroy(hd->cs); 81 hd->cs = NULL; 82 } 83 84 hd->multicast_ip = multicast_ip; 85 hd->multicast_port = 0; 86 hd->device_id = 0; 87 hd->tuner = 0; 88 hd->lockkey = 0; 89 90 unsigned long ip = multicast_ip; 91 sprintf(hd->name, "%lu.%lu.%lu.%lu", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF); 92 sprintf(hd->model, "multicast"); 93 94 return 1; 95 } 96 97 int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip) 98 { 99 if ((device_id == 0) && (device_ip == 0)) { 100 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: device not specified\n"); 101 return -1; 102 } 103 104 if (hdhomerun_discover_is_ip_multicast(device_ip)) { 105 return hdhomerun_device_set_device_multicast(hd, device_ip); 106 } 107 108 return hdhomerun_device_set_device_normal(hd, device_id, device_ip); 109 } 110 111 int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner) 112 { 113 if (hd->multicast_ip != 0) { 114 if (tuner != 0) { 115 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner: tuner cannot be specified in multicast mode\n"); 116 return -1; 117 } 118 119 return 1; 120 } 121 70 122 hd->tuner = tuner; 71 hdhomerun_device_set_update(hd); 123 sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner); 124 125 return 1; 72 126 } 73 127 74 128 struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg) 75 129 { 76 130 struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)calloc(1, sizeof(struct hdhomerun_device_t)); 77 131 if (!hd) { 78 hdhomerun_debug_printf( dbg, "hdhomerun_device_create: failed to allocate device object\n");132 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_create: failed to allocate device object\n"); 79 133 return NULL; 80 134 } 81 135 82 136 hd->dbg = dbg; 83 137 84 hd->cs = hdhomerun_control_create(0, 0, hd->dbg); 85 if (!hd->cs) { 86 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_create: failed to create control object\n"); 138 if ((device_id == 0) && (device_ip == 0) && (tuner == 0)) { 139 return hd; 140 } 141 142 if (hdhomerun_device_set_device(hd, device_id, device_ip) <= 0) { 87 143 free(hd); 88 144 return NULL; 89 145 } 146 if (hdhomerun_device_set_tuner(hd, tuner) <= 0) { 147 free(hd); 148 return NULL; 149 } 90 150 91 hdhomerun_device_set_device(hd, device_id, device_ip);92 hdhomerun_device_set_tuner(hd, tuner);93 94 151 return hd; 95 152 } 96 153 … … 104 161 hdhomerun_video_destroy(hd->vs); 105 162 } 106 163 107 hdhomerun_control_destroy(hd->cs); 164 if (hd->cs) { 165 hdhomerun_control_destroy(hd->cs); 166 } 108 167 109 168 free(hd); 110 169 } … … 156 215 static struct hdhomerun_device_t *hdhomerun_device_create_from_str_ip(const char *device_str, struct hdhomerun_debug_t *dbg) 157 216 { 158 217 unsigned long a[4]; 159 unsigned int tuner; 160 161 if (sscanf(device_str, "%lu.%lu.%lu.%lu-%u", &a[0], &a[1], &a[2], &a[3], &tuner) != 5) { 162 tuner = 0; 218 unsigned int port = 0; 219 if (sscanf(device_str, "%lu.%lu.%lu.%lu:%u", &a[0], &a[1], &a[2], &a[3], &port) != 5) { 163 220 if (sscanf(device_str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) { 164 221 return NULL; 165 222 } 166 223 } 167 224 168 225 unsigned long device_ip = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0); 169 return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, tuner, dbg); 226 struct hdhomerun_device_t *hd = hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, 0, dbg); 227 if (!hd) { 228 return NULL; 229 } 230 231 if (hd->multicast_ip != 0) { 232 hd->multicast_port = port; 233 } 234 235 return hd; 170 236 } 171 237 172 238 static struct hdhomerun_device_t *hdhomerun_device_create_from_str_dns(const char *device_str, struct hdhomerun_debug_t *dbg) … … 239 305 240 306 uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd) 241 307 { 242 return hd homerun_control_get_device_id(hd->cs);308 return hd->device_id; 243 309 } 244 310 245 311 uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd) 246 312 { 247 return hdhomerun_control_get_device_ip(hd->cs); 313 if (hd->multicast_ip != 0) { 314 return hd->multicast_ip; 315 } 316 if (hd->cs) { 317 return hdhomerun_control_get_device_ip(hd->cs); 318 } 319 320 return 0; 248 321 } 249 322 250 323 uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd) 251 324 { 252 return hdhomerun_control_get_device_id_requested(hd->cs); 325 if (hd->multicast_ip != 0) { 326 return 0; 327 } 328 if (hd->cs) { 329 return hdhomerun_control_get_device_id_requested(hd->cs); 330 } 331 332 return 0; 253 333 } 254 334 255 335 uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd) 256 336 { 257 return hdhomerun_control_get_device_ip_requested(hd->cs); 337 if (hd->multicast_ip != 0) { 338 return hd->multicast_ip; 339 } 340 if (hd->cs) { 341 return hdhomerun_control_get_device_ip_requested(hd->cs); 342 } 343 344 return 0; 258 345 } 259 346 260 347 unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd) … … 273 360 return hd->vs; 274 361 } 275 362 276 hd->vs = hdhomerun_video_create( 0, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg);363 hd->vs = hdhomerun_video_create(hd->multicast_port, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg); 277 364 if (!hd->vs) { 278 365 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_video_sock: failed to create video object\n"); 279 366 return NULL; … … 284 371 285 372 uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd) 286 373 { 287 return hdhomerun_control_get_local_addr(hd->cs); 374 if (hd->cs) { 375 return hdhomerun_control_get_local_addr(hd->cs); 376 } 377 378 return 0; 288 379 } 289 380 290 381 static uint32_t hdhomerun_device_get_status_parse(const char *status_str, const char *tag) … … 368 459 369 460 int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status) 370 461 { 462 if (!hd->cs) { 463 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_status: device not set\n"); 464 return -1; 465 } 466 371 467 memset(status, 0, sizeof(struct hdhomerun_tuner_status_t)); 372 468 373 469 char name[32]; … … 414 510 415 511 int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo) 416 512 { 513 if (!hd->cs) { 514 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_streaminfo: device not set\n"); 515 return -1; 516 } 517 417 518 char name[32]; 418 519 sprintf(name, "/tuner%u/streaminfo", hd->tuner); 419 520 return hdhomerun_control_get(hd->cs, name, pstreaminfo, NULL); … … 421 522 422 523 int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel) 423 524 { 525 if (!hd->cs) { 526 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_channel: device not set\n"); 527 return -1; 528 } 529 424 530 char name[32]; 425 531 sprintf(name, "/tuner%u/channel", hd->tuner); 426 532 return hdhomerun_control_get(hd->cs, name, pchannel, NULL); … … 428 534 429 535 int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap) 430 536 { 537 if (!hd->cs) { 538 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_channelmap: device not set\n"); 539 return -1; 540 } 541 431 542 char name[32]; 432 543 sprintf(name, "/tuner%u/channelmap", hd->tuner); 433 544 return hdhomerun_control_get(hd->cs, name, pchannelmap, NULL); … … 435 546 436 547 int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter) 437 548 { 549 if (!hd->cs) { 550 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_filter: device not set\n"); 551 return -1; 552 } 553 438 554 char name[32]; 439 555 sprintf(name, "/tuner%u/filter", hd->tuner); 440 556 return hdhomerun_control_get(hd->cs, name, pfilter, NULL); … … 442 558 443 559 int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram) 444 560 { 561 if (!hd->cs) { 562 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_program: device not set\n"); 563 return -1; 564 } 565 445 566 char name[32]; 446 567 sprintf(name, "/tuner%u/program", hd->tuner); 447 568 return hdhomerun_control_get(hd->cs, name, pprogram, NULL); … … 449 570 450 571 int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget) 451 572 { 573 if (!hd->cs) { 574 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_target: device not set\n"); 575 return -1; 576 } 577 452 578 char name[32]; 453 579 sprintf(name, "/tuner%u/target", hd->tuner); 454 580 return hdhomerun_control_get(hd->cs, name, ptarget, NULL); … … 456 582 457 583 int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount) 458 584 { 585 if (!hd->cs) { 586 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_plotsample: device not set\n"); 587 return -1; 588 } 589 459 590 char name[32]; 460 591 sprintf(name, "/tuner%u/plotsample", hd->tuner); 461 592 … … 505 636 506 637 int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner) 507 638 { 639 if (!hd->cs) { 640 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_lockkey_owner: device not set\n"); 641 return -1; 642 } 643 508 644 char name[32]; 509 645 sprintf(name, "/tuner%u/lockkey", hd->tuner); 510 646 return hdhomerun_control_get(hd->cs, name, powner, NULL); … … 512 648 513 649 int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget) 514 650 { 651 if (!hd->cs) { 652 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_ir_target: device not set\n"); 653 return -1; 654 } 655 515 656 return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL); 516 657 } 517 658 518 659 int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation) 519 660 { 661 if (!hd->cs) { 662 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_lineup_location: device not set\n"); 663 return -1; 664 } 665 520 666 return hdhomerun_control_get(hd->cs, "/lineup/location", plocation, NULL); 521 667 } 522 668 523 669 int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num) 524 670 { 671 if (!hd->cs) { 672 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_version: device not set\n"); 673 return -1; 674 } 675 525 676 char *version_str; 526 677 int ret = hdhomerun_control_get(hd->cs, "/sys/version", &version_str, NULL); 527 678 if (ret <= 0) { … … 544 695 return 1; 545 696 } 546 697 698 int hdhomerun_device_get_supported(struct hdhomerun_device_t *hd, char *prefix, char **pstr) 699 { 700 if (!hd->cs) { 701 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channel: device not set\n"); 702 return -1; 703 } 704 705 char *features; 706 int ret = hdhomerun_control_get(hd->cs, "/sys/features", &features, NULL); 707 if (ret <= 0) { 708 return ret; 709 } 710 711 if (!prefix) { 712 *pstr = features; 713 return 1; 714 } 715 716 char *ptr = strstr(features, prefix); 717 if (!ptr) { 718 return 0; 719 } 720 721 ptr += strlen(prefix); 722 *pstr = ptr; 723 724 ptr = strchr(ptr, '\n'); 725 if (ptr) { 726 *ptr = 0; 727 } 728 729 return 1; 730 } 731 547 732 int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel) 548 733 { 734 if (!hd->cs) { 735 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channel: device not set\n"); 736 return -1; 737 } 738 549 739 char name[32]; 550 740 sprintf(name, "/tuner%u/channel", hd->tuner); 551 741 return hdhomerun_control_set_with_lockkey(hd->cs, name, channel, hd->lockkey, NULL, NULL); … … 553 743 554 744 int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap) 555 745 { 746 if (!hd->cs) { 747 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channelmap: device not set\n"); 748 return -1; 749 } 750 556 751 char name[32]; 557 752 sprintf(name, "/tuner%u/channelmap", hd->tuner); 558 753 return hdhomerun_control_set_with_lockkey(hd->cs, name, channelmap, hd->lockkey, NULL, NULL); … … 560 755 561 756 int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter) 562 757 { 758 if (!hd->cs) { 759 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_filter: device not set\n"); 760 return -1; 761 } 762 563 763 char name[32]; 564 764 sprintf(name, "/tuner%u/filter", hd->tuner); 565 765 return hdhomerun_control_set_with_lockkey(hd->cs, name, filter, hd->lockkey, NULL, NULL); … … 635 835 636 836 int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program) 637 837 { 838 if (!hd->cs) { 839 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_program: device not set\n"); 840 return -1; 841 } 842 638 843 char name[32]; 639 844 sprintf(name, "/tuner%u/program", hd->tuner); 640 845 return hdhomerun_control_set_with_lockkey(hd->cs, name, program, hd->lockkey, NULL, NULL); … … 642 847 643 848 int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target) 644 849 { 850 if (!hd->cs) { 851 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target: device not set\n"); 852 return -1; 853 } 854 645 855 char name[32]; 646 856 sprintf(name, "/tuner%u/target", hd->tuner); 647 857 return hdhomerun_control_set_with_lockkey(hd->cs, name, target, hd->lockkey, NULL, NULL); 648 858 } 649 859 650 int hdhomerun_device_set_tuner_target_to_local_protocol(struct hdhomerun_device_t *hd, const char *protocol)860 static int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd, const char *protocol) 651 861 { 652 /* Create video socket. */ 653 hdhomerun_device_get_video_sock(hd); 862 if (!hd->cs) { 863 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target_to_local: device not set\n"); 864 return -1; 865 } 654 866 if (!hd->vs) { 867 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target_to_local: video not initialized\n"); 655 868 return -1; 656 869 } 657 870 … … 669 882 return hdhomerun_device_set_tuner_target(hd, target); 670 883 } 671 884 672 int hdhomerun_device_set_ tuner_target_to_local(struct hdhomerun_device_t *hd)885 int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target) 673 886 { 674 return hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_UDP); 675 } 887 if (!hd->cs) { 888 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_ir_target: device not set\n"); 889 return -1; 890 } 676 891 677 int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target)678 {679 892 return hdhomerun_control_set(hd->cs, "/ir/target", target, NULL, NULL); 680 893 } 681 894 682 895 int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location) 683 896 { 897 if (!hd->cs) { 898 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_lineup_location: device not set\n"); 899 return -1; 900 } 901 684 902 return hdhomerun_control_set(hd->cs, "/lineup/location", location, NULL, NULL); 685 903 } 686 904 905 int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list) 906 { 907 if (!hd->cs) { 908 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_sys_dvbc_modulation: device not set\n"); 909 return -1; 910 } 911 912 return hdhomerun_control_set(hd->cs, "/sys/dvbc_modulation", modulation_list, NULL, NULL); 913 } 914 687 915 int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror) 688 916 { 917 if (!hd->cs) { 918 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_var: device not set\n"); 919 return -1; 920 } 921 689 922 return hdhomerun_control_get(hd->cs, name, pvalue, perror); 690 923 } 691 924 692 925 int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror) 693 926 { 927 if (!hd->cs) { 928 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_var: device not set\n"); 929 return -1; 930 } 931 694 932 return hdhomerun_control_set_with_lockkey(hd->cs, name, value, hd->lockkey, pvalue, perror); 695 933 } 696 934 697 935 int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror) 698 936 { 937 if (hd->multicast_ip != 0) { 938 return 1; 939 } 940 if (!hd->cs) { 941 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_request: device not set\n"); 942 return -1; 943 } 944 699 945 uint32_t new_lockkey = (uint32_t)getcurrenttime(); 700 946 701 947 char name[32]; … … 716 962 717 963 int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd) 718 964 { 965 if (hd->multicast_ip != 0) { 966 return 1; 967 } 968 if (!hd->cs) { 969 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_release: device not set\n"); 970 return -1; 971 } 972 719 973 if (hd->lockkey == 0) { 720 974 return 1; 721 975 } … … 730 984 731 985 int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd) 732 986 { 987 if (hd->multicast_ip != 0) { 988 return 1; 989 } 990 if (!hd->cs) { 991 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_force: device not set\n"); 992 return -1; 993 } 994 733 995 char name[32]; 734 996 sprintf(name, "/tuner%u/lockkey", hd->tuner); 735 997 int ret = hdhomerun_control_set(hd->cs, name, "force", NULL, NULL); … … 740 1002 741 1003 void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey) 742 1004 { 1005 if (hd->multicast_ip != 0) { 1006 return; 1007 } 1008 743 1009 hd->lockkey = lockkey; 744 1010 } 745 1011 746 1012 int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status) 747 1013 { 748 1014 /* Delay for SS reading to be valid (signal present). */ 749 msleep (250);1015 msleep_minimum(250); 750 1016 751 1017 /* Wait for up to 2.5 seconds for lock. */ 752 1018 uint64_t timeout = getcurrenttime() + 2500; … … 768 1034 return 1; 769 1035 } 770 1036 771 msleep (250);1037 msleep_approx(250); 772 1038 } 773 1039 } 774 1040 775 1041 int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd) 776 1042 { 1043 hdhomerun_device_get_video_sock(hd); 1044 if (!hd->vs) { 1045 return -1; 1046 } 1047 777 1048 /* Set target. */ 778 int ret = hdhomerun_device_stream_refresh_target(hd); 779 if (ret <= 0) { 780 return ret; 1049 if (hd->multicast_ip != 0) { 1050 int ret = hdhomerun_video_join_multicast_group(hd->vs, hd->multicast_ip, 0); 1051 if (ret <= 0) { 1052 return ret; 1053 } 1054 } else { 1055 int ret = hdhomerun_device_set_tuner_target_to_local(hd, HDHOMERUN_TARGET_PROTOCOL_RTP); 1056 if (ret == 0) { 1057 ret = hdhomerun_device_set_tuner_target_to_local(hd, HDHOMERUN_TARGET_PROTOCOL_UDP); 1058 } 1059 if (ret <= 0) { 1060 return ret; 1061 } 781 1062 } 782 1063 783 1064 /* Flush video buffer. */ 784 msleep (64);1065 msleep_minimum(64); 785 1066 hdhomerun_video_flush(hd->vs); 786 1067 787 1068 /* Success. */ 788 1069 return 1; 789 1070 } 790 1071 791 int hdhomerun_device_stream_refresh_target(struct hdhomerun_device_t *hd)792 {793 int ret = hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_RTP);794 if (ret == 0) {795 ret = hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);796 }797 return ret;798 }799 800 1072 uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size) 801 1073 { 802 1074 if (!hd->vs) { 1075 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_recv: video not initialized\n"); 803 1076 return NULL; 804 1077 } 1078 805 1079 return hdhomerun_video_recv(hd->vs, max_size, pactual_size); 806 1080 } 807 1081 808 1082 void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd) 809 1083 { 1084 if (!hd->vs) { 1085 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_flush: video not initialized\n"); 1086 return; 1087 } 1088 810 1089 hdhomerun_video_flush(hd->vs); 811 1090 } 812 1091 813 1092 void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd) 814 1093 { 815 hdhomerun_device_set_tuner_target(hd, "none"); 1094 if (!hd->vs) { 1095 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_stop: video not initialized\n"); 1096 return; 1097 } 1098 1099 if (hd->multicast_ip != 0) { 1100 hdhomerun_video_leave_multicast_group(hd->vs); 1101 } else { 1102 hdhomerun_device_set_tuner_target(hd, "none"); 1103 } 816 1104 } 817 1105 818 1106 int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap) … … 823 1111 824 1112 hd->scan = channelscan_create(hd, channelmap); 825 1113 if (!hd->scan) { 1114 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_init: failed to create scan object\n"); 826 1115 return -1; 827 1116 } 828 1117 … … 832 1121 int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result) 833 1122 { 834 1123 if (!hd->scan) { 1124 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_advance: scan not initialized\n"); 835 1125 return 0; 836 1126 } 837 1127 … … 847 1137 int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result) 848 1138 { 849 1139 if (!hd->scan) { 1140 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_detect: scan not initialized\n"); 850 1141 return 0; 851 1142 } 852 1143 … … 862 1153 uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd) 863 1154 { 864 1155 if (!hd->scan) { 1156 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_get_progress: scan not initialized\n"); 865 1157 return 0; 866 1158 } 867 1159 868 1160 return channelscan_get_progress(hd->scan); 869 1161 } 870 1162 871 int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features)872 {873 uint32_t version;874 if (hdhomerun_device_get_version(hd, NULL, &version) <= 0) {875 return -1;876 }877 878 if (version < 20070219) {879 return 0;880 }881 882 return 1;883 }884 885 1163 const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd) 886 1164 { 887 1165 if (*hd->model) { 888 1166 return hd->model; 889 1167 } 890 1168 1169 if (!hd->cs) { 1170 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_model_str: device not set\n"); 1171 return NULL; 1172 } 1173 891 1174 char *model_str; 892 1175 int ret = hdhomerun_control_get(hd->cs, "/sys/model", &model_str, NULL); 893 1176 if (ret < 0) { … … 896 1179 if (ret == 0) { 897 1180 strncpy(hd->model, "hdhomerun_atsc", sizeof(hd->model) - 1); 898 1181 hd->model[sizeof(hd->model) - 1] = 0; 1182 return hd->model; 899 1183 } 900 else901 {902 strncpy(hd->model, model_str, sizeof(hd->model) - 1);903 hd->model[sizeof(hd->model) - 1] = 0;904 }905 1184 1185 strncpy(hd->model, model_str, sizeof(hd->model) - 1); 1186 hd->model[sizeof(hd->model) - 1] = 0; 906 1187 return hd->model; 907 1188 } 908 1189 909 1190 int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file) 910 1191 { 1192 if (!hd->cs) { 1193 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_upgrade: device not set\n"); 1194 return -1; 1195 } 1196 911 1197 hdhomerun_control_set(hd->cs, "/tuner0/lockkey", "force", NULL, NULL); 912 1198 hdhomerun_control_set(hd->cs, "/tuner0/channel", "none", NULL, NULL); 913 1199 … … 923 1209 return; 924 1210 } 925 1211 926 char name[32]; 927 sprintf(name, "/tuner%u/debug", hd->tuner); 1212 if (hd->cs) { 1213 char name[32]; 1214 sprintf(name, "/tuner%u/debug", hd->tuner); 928 1215 929 char *debug_str;930 char *error_str;931 int ret = hdhomerun_control_get(hd->cs, name, &debug_str, &error_str);932 if (ret < 0) {933 hdhomerun_debug_printf(hd->dbg, "video dev: communication error getting debug stats\n");934 return;935 }1216 char *debug_str; 1217 char *error_str; 1218 int ret = hdhomerun_control_get(hd->cs, name, &debug_str, &error_str); 1219 if (ret < 0) { 1220 hdhomerun_debug_printf(hd->dbg, "video dev: communication error getting debug stats\n"); 1221 return; 1222 } 936 1223 937 if (error_str) { 938 hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", error_str); 939 } else { 940 hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", debug_str); 1224 if (error_str) { 1225 hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", error_str); 1226 } else { 1227 hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", debug_str); 1228 } 941 1229 } 942 1230 943 1231 if (hd->vs) { … … 947 1235 948 1236 void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats) 949 1237 { 1238 if (!hd->vs) { 1239 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_flush: video not initialized\n"); 1240 memset(stats, 0, sizeof(struct hdhomerun_video_stats_t)); 1241 return; 1242 } 1243 950 1244 hdhomerun_video_get_stats(hd->vs, stats); 951 1245 } -
hdhomerun_device_selector.c
1 1 /* 2 2 * hdhomerun_device_selector.c 3 3 * 4 * Copyright © 2009 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2009-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 68 68 free(hds); 69 69 } 70 70 71 LIBTYPE int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds) 72 { 73 return (int)hds->hd_count; 74 } 75 71 76 void hdhomerun_device_selector_add_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd) 72 77 { 73 78 size_t index; … … 129 134 return NULL; 130 135 } 131 136 132 voidhdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename)137 int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename) 133 138 { 134 139 FILE *fp = fopen(filename, "r"); 135 140 if (!fp) { 136 return ;141 return 0; 137 142 } 138 143 139 144 while(1) { … … 151 156 } 152 157 153 158 fclose(fp); 159 return (int)hds->hd_count; 154 160 } 155 161 156 162 #if defined(__WINDOWS__) 157 voidhdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource)163 int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource) 158 164 { 159 165 HKEY tuners_key; 160 166 LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Silicondust\\HDHomeRun\\Tuners", 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &tuners_key); 161 167 if (ret != ERROR_SUCCESS) { 162 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open tuners registry key (%ld)\n", ret);163 return ;168 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open tuners registry key (%ld)\n", (long)ret); 169 return 0; 164 170 } 165 171 166 172 DWORD index = 0; … … 177 183 HKEY device_key; 178 184 ret = RegOpenKeyEx(tuners_key, wdevice_name, 0, KEY_QUERY_VALUE, &device_key); 179 185 if (ret != ERROR_SUCCESS) { 180 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open registry key for %S (%ld)\n", wdevice_name, ret);186 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open registry key for %S (%ld)\n", wdevice_name, (long)ret); 181 187 continue; 182 188 } 183 189 … … 207 213 } 208 214 209 215 RegCloseKey(tuners_key); 216 return (int)hds->hd_count; 210 217 } 211 218 #endif 212 219 … … 268 275 /* 269 276 * Test local port. 270 277 */ 271 int test_sock = (int)socket(AF_INET, SOCK_DGRAM, 0);272 if (test_sock == -1) {278 hdhomerun_sock_t test_sock = hdhomerun_sock_create_udp(); 279 if (test_sock == HDHOMERUN_SOCK_INVALID) { 273 280 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to create test sock\n", name); 274 281 return FALSE; 275 282 } 276 283 277 struct sockaddr_in sock_addr; 278 memset(&sock_addr, 0, sizeof(sock_addr)); 279 sock_addr.sin_family = AF_INET; 280 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 281 sock_addr.sin_port = htons((uint16_t)target_port); 282 ret = bind(test_sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); 283 close(test_sock); 284 bool_t inuse = (hdhomerun_sock_bind(test_sock, INADDR_ANY, (uint16_t)target_port) == FALSE); 285 hdhomerun_sock_destroy(test_sock); 284 286 285 if ( ret != 0) {287 if (inuse) { 286 288 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine\n", name); 287 289 return FALSE; 288 290 } -
hdhomerun_os_windows.h
1 1 /* 2 2 * hdhomerun_os_windows.h 3 3 * 4 * Copyright © 2006-2008Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 31 31 */ 32 32 33 33 #define _WINSOCKAPI_ 34 // MinGW lacks wspiapi, so remove dependency by setting minimum WINVER to WinXP35 #define WINVER 0x050136 34 #include <windows.h> 37 35 #include <winsock2.h> 38 36 #include <ws2tcpip.h> 39 //#include <wspiapi.h>37 #include <wspiapi.h> 40 38 #include <stdlib.h> 41 39 #include <stdio.h> 42 40 #include <stdarg.h> … … 55 53 #endif 56 54 57 55 typedef int bool_t; 58 /* Use MinGW includes instead59 56 typedef signed __int8 int8_t; 60 57 typedef signed __int16 int16_t; 61 58 typedef signed __int32 int32_t; … … 64 61 typedef unsigned __int16 uint16_t; 65 62 typedef unsigned __int32 uint32_t; 66 63 typedef unsigned __int64 uint64_t; 64 typedef void (*sig_t)(int); 67 65 typedef HANDLE pthread_t; 68 66 typedef HANDLE pthread_mutex_t; 69 */70 #include <stdint.h>71 #include <pthread.h>72 67 73 // Avoid #define conflicts by limiting scope to non-c++ 74 #ifndef __cplusplus 75 #define socklen_t int 76 #define close closesocket 77 #define sock_getlasterror WSAGetLastError() 78 #define sock_getlasterror_socktimeout (WSAGetLastError() == WSAETIMEDOUT) 79 //#define va_copy(x, y) x = y 68 #define va_copy(x, y) x = y 80 69 #define atoll _atoi64 81 70 #define strdup _strdup 82 71 #define strcasecmp _stricmp … … 84 73 #define fseeko _fseeki64 85 74 #define ftello _ftelli64 86 75 #define THREAD_FUNC_PREFIX DWORD WINAPI 87 #define SIGPIPE SIGABRT 76 77 #ifdef __cplusplus 78 extern "C" { 88 79 #endif 89 80 90 static inline uint64_t getcurrenttime(void) 91 { 92 struct timeb tb; 93 ftime(&tb); 94 return ((uint64_t)tb.time * 1000) + tb.millitm; 95 } 81 extern LIBTYPE uint64_t getcurrenttime(void); 82 extern LIBTYPE void msleep_approx(uint64_t ms); 83 extern LIBTYPE void msleep_minimum(uint64_t ms); 96 84 97 static inline int msleep(unsigned int ms) 98 { 99 uint64_t stop_time = getcurrenttime() + ms; 85 extern LIBTYPE int pthread_create(pthread_t *tid, void *attr, LPTHREAD_START_ROUTINE start, void *arg); 86 extern LIBTYPE int pthread_join(pthread_t tid, void **value_ptr); 87 extern LIBTYPE void pthread_mutex_init(pthread_mutex_t *mutex, void *attr); 88 extern LIBTYPE void pthread_mutex_lock(pthread_mutex_t *mutex); 89 extern LIBTYPE void pthread_mutex_unlock(pthread_mutex_t *mutex); 100 90 101 while (1) {102 uint64_t current_time = getcurrenttime();103 if (current_time >= stop_time) {104 return 0;105 }106 107 uint64_t delay_ms = stop_time - current_time;108 Sleep((DWORD)delay_ms);109 }110 }111 112 // Avoid a define conflict113 /*static inline int sleep(unsigned int sec)114 {115 msleep(sec * 1000);116 return 0;117 }118 */119 120 static inline int setsocktimeout(int s, int level, int optname, uint64_t timeout)121 {122 int t = (int)timeout;123 return setsockopt(s, level, optname, (char *)&t, sizeof(t));124 }125 126 /* MythTV uses pthreads lib instead127 static inline int pthread_create(pthread_t *tid, void *attr, LPTHREAD_START_ROUTINE start, void *arg)128 {129 *tid = CreateThread(NULL, 0, start, arg, 0, NULL);130 if (!*tid) {131 return (int)GetLastError();132 }133 return 0;134 }135 136 static inline int pthread_join(pthread_t tid, void **value_ptr)137 {138 while (1) {139 DWORD ExitCode = 0;140 if (!GetExitCodeThread(tid, &ExitCode)) {141 return (int)GetLastError();142 }143 if (ExitCode != STILL_ACTIVE) {144 return 0;145 }146 }147 }148 149 static inline void pthread_mutex_init(pthread_mutex_t *mutex, void *attr)150 {151 *mutex = CreateMutex(NULL, FALSE, NULL);152 }153 154 static inline void pthread_mutex_lock(pthread_mutex_t *mutex)155 {156 WaitForSingleObject(*mutex, INFINITE);157 }158 159 static inline void pthread_mutex_unlock(pthread_mutex_t *mutex)160 {161 ReleaseMutex(*mutex);162 }163 */164 165 91 /* 166 92 * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing. 167 93 * Attempting to restore on exit fails to restore if the program is terminated by the user. 168 94 * Solution - set the output format each printf. 169 95 */ 170 static inline void console_vprintf(const char *fmt, va_list ap) 171 { 172 UINT cp = GetConsoleOutputCP(); 173 SetConsoleOutputCP(CP_UTF8); 174 vprintf(fmt, ap); 175 SetConsoleOutputCP(cp); 176 } 96 extern LIBTYPE void console_vprintf(const char *fmt, va_list ap); 97 extern LIBTYPE void console_printf(const char *fmt, ...); 177 98 178 static inline void console_printf(const char *fmt, ...) 179 { 180 va_list ap; 181 va_start(ap, fmt); 182 console_vprintf(fmt, ap); 183 va_end(ap); 99 #ifdef __cplusplus 184 100 } 101 #endif -
hdhomerun_channels.h
1 1 /* 2 2 * hdhomerun_channels.h 3 3 * 4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 37 37 struct hdhomerun_channel_entry_t; 38 38 struct hdhomerun_channel_list_t; 39 39 40 extern LIBTYPE const char *hdhomerun_channelmap_ convert_countrycode_to_channelmap_prefix(const char *countrycode);40 extern LIBTYPE const char *hdhomerun_channelmap_get_channelmap_from_country_source(const char *countrycode, const char *source); 41 41 extern LIBTYPE const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelmap); 42 42 43 43 extern LIBTYPE uint8_t hdhomerun_channel_entry_channel_number(struct hdhomerun_channel_entry_t *entry); -
hdhomerun_pkt.h
1 1 /* 2 2 * hdhomerun_pkt.h 3 3 * 4 * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public -
hdhomerun_device_selector.h
43 43 extern LIBTYPE void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, bool_t destroy_devices); 44 44 45 45 /* 46 * Get the number of devices in the list. 47 */ 48 extern LIBTYPE int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds); 49 50 /* 46 51 * Populate device selector with devices from given source. 52 * Returns the number of devices populated. 47 53 */ 48 extern LIBTYPE voidhdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename);54 extern LIBTYPE int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename); 49 55 #if defined(__WINDOWS__) 50 extern LIBTYPE voidhdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource);56 extern LIBTYPE int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource); 51 57 #endif 52 58 53 59 /* -
hdhomerun_device.h
1 1 /* 2 2 * hdhomerun_device.h 3 3 * 4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 51 51 * GUI feedback to the user of the selected tuner might use 5 device objects: 4 for streaming video 52 52 * (one per thread) and one for the GUI display that can switch between tuners. 53 53 * 54 * This function will not attempt to connect to the device. 55 * The connection will be established when first used. 54 * This function will not attempt to connect to the device. The connection will be established when first used. 56 55 * 57 56 * uint32_t device_id = 32-bit device id of device. Set to HDHOMERUN_DEVICE_ID_WILDCARD to match any device ID. 58 57 * uint32_t device_ip = IP address of device. Set to 0 to auto-detect. … … 68 67 * <device id> 69 68 * <device id>-<tuner index> 70 69 * <ip address> 71 * If the tuner index is not included in the device_str then it is set to zero. 72 * Use hdhomerun_device_set_tuneror hdhomerun_device_set_tuner_from_str to set the tuner.70 * If the tuner index is not included in the device_str then it is set to zero. Use hdhomerun_device_set_tuner 71 * or hdhomerun_device_set_tuner_from_str to set the tuner. 73 72 * 74 73 * The hdhomerun_device_set_tuner_from_str function sets the tuner from the given tuner_str. 75 74 * The tuner_str parameter can be any of the following forms: … … 90 89 extern LIBTYPE uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd); 91 90 extern LIBTYPE unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd); 92 91 93 extern LIBTYPE voidhdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip);94 extern LIBTYPE voidhdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);92 extern LIBTYPE int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip); 93 extern LIBTYPE int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner); 95 94 extern LIBTYPE int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str); 96 95 97 96 /* … … 126 125 extern LIBTYPE int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget); 127 126 extern LIBTYPE int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation); 128 127 extern LIBTYPE int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num); 128 extern LIBTYPE int hdhomerun_device_get_supported(struct hdhomerun_device_t *hd, char *prefix, char **pstr); 129 129 130 130 extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status); 131 131 extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status); … … 148 148 extern LIBTYPE int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000]); 149 149 extern LIBTYPE int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program); 150 150 extern LIBTYPE int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target); 151 extern LIBTYPE int hdhomerun_device_set_tuner_target_to_local_protocol(struct hdhomerun_device_t *hd, const char *protocol);152 extern LIBTYPE int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd);153 151 extern LIBTYPE int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target); 154 152 extern LIBTYPE int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location); 153 extern LIBTYPE int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list); 155 154 156 155 /* 157 156 * Get/set a named control variable on the device. … … 219 218 * Returns -1 if a communication error occurs. 220 219 * 221 220 * The hdhomerun_device_stream_recv function should be called periodically to receive the stream data. 222 * The buffer can losslessly store 1 second of data, however a more typical call rate would be every 64ms.221 * The buffer can losslessly store 1 second of data, however a more typical call rate would be every 15ms. 223 222 * 224 223 * The hdhomerun_device_stream_stop function tells the device to stop streaming data. 225 224 */ 226 225 extern LIBTYPE int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd); 227 extern LIBTYPE int hdhomerun_device_stream_refresh_target(struct hdhomerun_device_t *hd);228 226 extern LIBTYPE uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size); 229 227 extern LIBTYPE void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd); 230 228 extern LIBTYPE void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd); … … 238 236 extern LIBTYPE uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd); 239 237 240 238 /* 241 * Check that the device is running the recommended firmware.242 *243 * uint32_t features: Reserved for future use. Set to zero.244 *245 * Returns 1 if the firmware meets the minimum requriements for all operations.246 * Returns 0 if th firmware does not meet the minimum requriements for all operations.247 * Returns -1 if an error occurs.248 */249 extern LIBTYPE int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features);250 251 /*252 239 * Upload new firmware to the device. 253 240 * 254 241 * FILE *upgrade_file: File pointer to read from. The file must have been opened in binary mode for reading. -
hdhomerun_types.h
1 1 /* 2 2 * hdhomerun_types.h 3 3 * 4 * Copyright © 2008-2009 Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2008-2009 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public -
hdhomerun_control.c
1 1 /* 2 2 * hdhomerun_control.c 3 3 * 4 * Copyright © 2006Silicondust USA Inc. <www.silicondust.com>.4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>. 5 5 * 6 6 * This library is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU Lesser General Public … … 32 32 33 33 #include "hdhomerun.h" 34 34 35 #define HDHOMERUN_CONTROL_SEND_TIMEOUT 5000 36 #define HDHOMERUN_CONTROL_RECV_TIMEOUT 5000 35 #define HDHOMERUN_CONTROL_CONNECT_TIMEOUT 2500 36 #define HDHOMERUN_CONTROL_SEND_TIMEOUT 2500 37 #define HDHOMERUN_CONTROL_RECV_TIMEOUT 2500 37 38 #define HDHOMERUN_CONTROL_UPGRADE_TIMEOUT 20000 38 39 39 40 struct hdhomerun_control_sock_t { … … 41 42 uint32_t desired_device_ip; 42 43 uint32_t actual_device_id; 43 44 uint32_t actual_device_ip; 44 int sock;45 hdhomerun_sock_t sock; 45 46 struct hdhomerun_debug_t *dbg; 46 47 struct hdhomerun_pkt_t tx_pkt; 47 48 struct hdhomerun_pkt_t rx_pkt; … … 49 50 50 51 static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs) 51 52 { 52 if (cs->sock == -1) {53 if (cs->sock == HDHOMERUN_SOCK_INVALID) { 53 54 return; 54 55 } 55 56 56 close(cs->sock);57 cs->sock = -1;57 hdhomerun_sock_destroy(cs->sock); 58 cs->sock = HDHOMERUN_SOCK_INVALID; 58 59 } 59 60 60 61 void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip) … … 76 77 } 77 78 78 79 cs->dbg = dbg; 79 cs->sock = -1;80 cs->sock = HDHOMERUN_SOCK_INVALID; 80 81 hdhomerun_control_set_device(cs, device_id, device_ip); 81 82 82 83 return cs; … … 90 91 91 92 static bool_t hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs) 92 93 { 93 if (cs->sock != -1) {94 if (cs->sock != HDHOMERUN_SOCK_INVALID) { 94 95 return TRUE; 95 96 } 96 97 … … 98 99 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: no device specified\n"); 99 100 return FALSE; 100 101 } 102 if (hdhomerun_discover_is_ip_multicast(cs->desired_device_ip)) { 103 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: cannot use multicast ip address for device operations\n"); 104 return FALSE; 105 } 101 106 102 107 /* Find device. */ 103 108 struct hdhomerun_discover_device_t result; … … 109 114 cs->actual_device_id = result.device_id; 110 115 111 116 /* Create socket. */ 112 cs->sock = (int)socket(AF_INET, SOCK_STREAM, 0);113 if (cs->sock == -1) {114 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to create socket (%d)\n", sock_getlasterror);117 cs->sock = hdhomerun_sock_create_tcp(); 118 if (cs->sock == HDHOMERUN_SOCK_INVALID) { 119 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to create socket (%d)\n", hdhomerun_sock_getlasterror()); 115 120 return FALSE; 116 121 } 117 122 118 /* Set timeouts. */119 setsocktimeout(cs->sock, SOL_SOCKET, SO_SNDTIMEO, HDHOMERUN_CONTROL_SEND_TIMEOUT);120 setsocktimeout(cs->sock, SOL_SOCKET, SO_RCVTIMEO, HDHOMERUN_CONTROL_RECV_TIMEOUT);121 122 123 /* Initiate connection. */ 123 struct sockaddr_in sock_addr; 124 memset(&sock_addr, 0, sizeof(sock_addr)); 125 sock_addr.sin_family = AF_INET; 126 sock_addr.sin_addr.s_addr = htonl(cs->actual_device_ip); 127 sock_addr.sin_port = htons(HDHOMERUN_CONTROL_TCP_PORT); 128 if (connect(cs->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 129 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to connect (%d)\n", sock_getlasterror); 124 if (!hdhomerun_sock_connect(cs->sock, cs->actual_device_ip, HDHOMERUN_CONTROL_TCP_PORT, HDHOMERUN_CONTROL_CONNECT_TIMEOUT)) { 125 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to connect (%d)\n", hdhomerun_sock_getlasterror()); 130 126 hdhomerun_control_close_sock(cs); 131 127 return FALSE; 132 128 } … … 172 168 return 0; 173 169 } 174 170 175 struct sockaddr_in sock_addr; 176 socklen_t sockaddr_size = sizeof(sock_addr); 177 if (getsockname(cs->sock, (struct sockaddr*)&sock_addr, &sockaddr_size) != 0) { 178 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: getsockname failed (%d)\n", sock_getlasterror); 171 uint32_t addr = hdhomerun_sock_getsockname_addr(cs->sock); 172 if (addr == 0) { 173 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: getsockname failed (%d)\n", hdhomerun_sock_getlasterror()); 179 174 return 0; 180 175 } 181 176 182 return ntohl(sock_addr.sin_addr.s_addr);177 return addr; 183 178 } 184 179 185 static int hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt)180 static bool_t hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt) 186 181 { 187 int length = (int)(tx_pkt->end - tx_pkt->start); 188 if (send(cs->sock, (char *)tx_pkt->start, (int)length, 0) != length) { 189 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_sock: send failed (%d)\n", sock_getlasterror); 182 if (!hdhomerun_sock_send(cs->sock, tx_pkt->start, tx_pkt->end - tx_pkt->start, HDHOMERUN_CONTROL_SEND_TIMEOUT)) { 183 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_sock: send failed (%d)\n", hdhomerun_sock_getlasterror()); 190 184 hdhomerun_control_close_sock(cs); 191 return -1;185 return FALSE; 192 186 } 193 187 194 return 1;188 return TRUE; 195 189 } 196 190 197 static int hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *rx_pkt, uint16_t *ptype, uint64_t recv_timeout)191 static bool_t hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *rx_pkt, uint16_t *ptype, uint64_t recv_timeout) 198 192 { 199 193 uint64_t stop_time = getcurrenttime() + recv_timeout; 200 194 hdhomerun_pkt_reset(rx_pkt); 201 195 202 while (getcurrenttime() < stop_time) { 203 struct timeval t; 204 t.tv_sec = 0; 205 t.tv_usec = 250000; 206 207 fd_set readfds; 208 FD_ZERO(&readfds); 209 FD_SET(cs->sock, &readfds); 210 211 if (select(cs->sock+1, &readfds, NULL, NULL, &t) < 0) { 212 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: select failed (%d)\n", sock_getlasterror); 196 while (1) { 197 uint64_t current_time = getcurrenttime(); 198 if (current_time >= stop_time) { 199 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: timeout\n"); 213 200 hdhomerun_control_close_sock(cs); 214 return -1;201 return FALSE; 215 202 } 216 217 if (!FD_ISSET(cs->sock, &readfds)) { 218 continue; 219 } 220 221 int rx_length = recv(cs->sock, (char *)rx_pkt->end, (int)(rx_pkt->limit - rx_pkt->end), 0); 222 if (rx_length <= 0) { 223 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: recv failed (%d)\n", sock_getlasterror); 203 204 size_t length = rx_pkt->limit - rx_pkt->end; 205 if (!hdhomerun_sock_recv(cs->sock, rx_pkt->end, &length, stop_time - current_time)) { 206 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: recv failed (%d)\n", hdhomerun_sock_getlasterror()); 224 207 hdhomerun_control_close_sock(cs); 225 return -1;208 return FALSE; 226 209 } 227 rx_pkt->end += rx_length;228 210 211 rx_pkt->end += length; 212 229 213 int ret = hdhomerun_pkt_open_frame(rx_pkt, ptype); 230 214 if (ret < 0) { 231 215 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: frame error\n"); 232 216 hdhomerun_control_close_sock(cs); 233 return -1;217 return FALSE; 234 218 } 235 if (ret ==0) {236 continue;219 if (ret > 0) { 220 return TRUE; 237 221 } 238 239 return 1;240 222 } 241 242 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: timeout\n");243 hdhomerun_control_close_sock(cs);244 return -1;245 223 } 246 224 247 225 static int hdhomerun_control_send_recv_internal(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt, struct hdhomerun_pkt_t *rx_pkt, uint16_t type, uint64_t recv_timeout) … … 250 228 251 229 int i; 252 230 for (i = 0; i < 2; i++) { 253 if (cs->sock == -1) {231 if (cs->sock == HDHOMERUN_SOCK_INVALID) { 254 232 if (!hdhomerun_control_connect_sock(cs)) { 255 233 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_recv: connect failed\n"); 256 234 return -1; 257 235 } 258 236 } 259 237 260 if ( hdhomerun_control_send_sock(cs, tx_pkt) < 0) {238 if (!hdhomerun_control_send_sock(cs, tx_pkt)) { 261 239 continue; 262 240 } 263 241 if (!rx_pkt) { … … 265 243 } 266 244 267 245 uint16_t rsp_type; 268 if ( hdhomerun_control_recv_sock(cs, rx_pkt, &rsp_type, recv_timeout) < 0) {246 if (!hdhomerun_control_recv_sock(cs, rx_pkt, &rsp_type, recv_timeout)) { 269 247 continue; 270 248 } 271 249 if (rsp_type != type + 1) { -
hdhomerun_sock_posix.c
1 /* 2 * hdhomerun_sock_posix.c 3 * 4 * Copyright © 2010 Silicondust USA Inc. <www.silicondust.com>. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 3 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * As a special exception to the GNU Lesser General Public License, 20 * you may link, statically or dynamically, an application with a 21 * publicly distributed version of the Library to produce an 22 * executable file containing portions of the Library, and 23 * distribute that executable file under terms of your choice, 24 * without any of the additional requirements listed in clause 4 of 25 * the GNU Lesser General Public License. 26 * 27 * By "a publicly distributed version of the Library", we mean 28 * either the unmodified Library as distributed by Silicondust, or a 29 * modified version of the Library that is distributed under the 30 * conditions defined in the GNU Lesser General Public License. 31 */ 32 33 /* 34 * Implementation notes: 35 * 36 * API specifies timeout for each operation (or zero for non-blocking). 37 * 38 * It is not possible to rely on the OS socket timeout as this will fail to 39 * detect the command-response situation where data is sent successfully and 40 * the other end chooses not to send a response (other than the TCP ack). 41 * 42 * The select() cannot be used with high socket numbers (typically max 1024) 43 * so the code works as follows: 44 * - Use non-blocking sockets to allow operation without select. 45 * - Use select where safe (low socket numbers). 46 * - Poll with short sleep when select cannot be used safely. 47 */ 48 49 #include "hdhomerun.h" 50 51 hdhomerun_sock_t hdhomerun_sock_create_udp(void) 52 { 53 /* Create socket. */ 54 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_DGRAM, 0); 55 if (sock == -1) { 56 return HDHOMERUN_SOCK_INVALID; 57 } 58 59 /* Set non-blocking */ 60 if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) { 61 close(sock); 62 return HDHOMERUN_SOCK_INVALID; 63 } 64 65 /* Allow broadcast. */ 66 int sock_opt = 1; 67 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt)); 68 69 /* Success. */ 70 return sock; 71 } 72 73 hdhomerun_sock_t hdhomerun_sock_create_tcp(void) 74 { 75 /* Create socket. */ 76 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_STREAM, 0); 77 if (sock == -1) { 78 return HDHOMERUN_SOCK_INVALID; 79 } 80 81 /* Set non-blocking */ 82 if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) { 83 close(sock); 84 return HDHOMERUN_SOCK_INVALID; 85 } 86 87 /* Success. */ 88 return sock; 89 } 90 91 void hdhomerun_sock_destroy(hdhomerun_sock_t sock) 92 { 93 close(sock); 94 } 95 96 int hdhomerun_sock_getlasterror(void) 97 { 98 return errno; 99 } 100 101 uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock) 102 { 103 struct sockaddr_in sock_addr; 104 socklen_t sockaddr_size = sizeof(sock_addr); 105 106 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 107 return 0; 108 } 109 110 return ntohl(sock_addr.sin_addr.s_addr); 111 } 112 113 uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock) 114 { 115 struct sockaddr_in sock_addr; 116 socklen_t sockaddr_size = sizeof(sock_addr); 117 118 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 119 return 0; 120 } 121 122 return ntohs(sock_addr.sin_port); 123 } 124 125 uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock) 126 { 127 struct sockaddr_in sock_addr; 128 socklen_t sockaddr_size = sizeof(sock_addr); 129 130 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 131 return 0; 132 } 133 134 return ntohl(sock_addr.sin_addr.s_addr); 135 } 136 137 #if defined(__CYGWIN__) 138 uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name) 139 { 140 return 0; 141 } 142 #else 143 uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name) 144 { 145 struct addrinfo hints; 146 memset(&hints, 0, sizeof(hints)); 147 hints.ai_family = AF_INET; 148 hints.ai_socktype = SOCK_STREAM; 149 hints.ai_protocol = IPPROTO_TCP; 150 151 struct addrinfo *sock_info; 152 if (getaddrinfo(name, "", &hints, &sock_info) != 0) { 153 return 0; 154 } 155 156 struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr; 157 uint32_t addr = ntohl(sock_addr->sin_addr.s_addr); 158 159 freeaddrinfo(sock_info); 160 return addr; 161 } 162 #endif 163 164 bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port) 165 { 166 struct sockaddr_in sock_addr; 167 memset(&sock_addr, 0, sizeof(sock_addr)); 168 sock_addr.sin_family = AF_INET; 169 sock_addr.sin_addr.s_addr = htonl(local_addr); 170 sock_addr.sin_port = htons(local_port); 171 172 if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 173 return FALSE; 174 } 175 176 return TRUE; 177 } 178 179 static bool_t hdhomerun_sock_wait_for_read_event(hdhomerun_sock_t sock, uint64_t stop_time) 180 { 181 uint64_t current_time = getcurrenttime(); 182 if (current_time >= stop_time) { 183 return FALSE; 184 } 185 186 if (sock < FD_SETSIZE) { 187 uint64_t timeout = stop_time - current_time; 188 struct timeval t; 189 t.tv_sec = timeout / 1000; 190 t.tv_usec = (timeout % 1000) * 1000; 191 192 fd_set readfds; 193 FD_ZERO(&readfds); 194 FD_SET(sock, &readfds); 195 196 fd_set errorfds; 197 FD_ZERO(&errorfds); 198 FD_SET(sock, &errorfds); 199 200 if (select(sock + 1, &readfds, NULL, &errorfds, &t) <= 0) { 201 return FALSE; 202 } 203 if (!FD_ISSET(sock, &readfds)) { 204 return FALSE; 205 } 206 } else { 207 uint64_t delay = stop_time - current_time; 208 if (delay > 5) { 209 delay = 5; 210 } 211 212 msleep_approx(delay); 213 } 214 215 return TRUE; 216 } 217 218 static bool_t hdhomerun_sock_wait_for_write_event(hdhomerun_sock_t sock, uint64_t stop_time) 219 { 220 uint64_t current_time = getcurrenttime(); 221 if (current_time >= stop_time) { 222 return FALSE; 223 } 224 225 if (sock < FD_SETSIZE) { 226 uint64_t timeout = stop_time - current_time; 227 struct timeval t; 228 t.tv_sec = timeout / 1000; 229 t.tv_usec = (timeout % 1000) * 1000; 230 231 fd_set writefds; 232 FD_ZERO(&writefds); 233 FD_SET(sock, &writefds); 234 235 fd_set errorfds; 236 FD_ZERO(&errorfds); 237 FD_SET(sock, &errorfds); 238 239 if (select(sock + 1, NULL, &writefds, &errorfds, &t) <= 0) { 240 return FALSE; 241 } 242 if (!FD_ISSET(sock, &writefds)) { 243 return FALSE; 244 } 245 } else { 246 uint64_t delay = stop_time - current_time; 247 if (delay > 5) { 248 delay = 5; 249 } 250 251 msleep_approx(delay); 252 } 253 254 return TRUE; 255 } 256 257 bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout) 258 { 259 struct sockaddr_in sock_addr; 260 memset(&sock_addr, 0, sizeof(sock_addr)); 261 sock_addr.sin_family = AF_INET; 262 sock_addr.sin_addr.s_addr = htonl(remote_addr); 263 sock_addr.sin_port = htons(remote_port); 264 265 if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == 0) { 266 return TRUE; 267 } 268 269 uint64_t stop_time = getcurrenttime() + timeout; 270 271 /* 272 * getpeername() is used to detect if connect succeeded. Bug - cygwin 273 * will return getpeername success even if the connect process hasn't 274 * completed. This first call to select is used to work around the 275 * problem (at least for low numbered sockets where select is used). 276 */ 277 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) { 278 return FALSE; 279 } 280 281 while (1) { 282 struct sockaddr_in sock_addr; 283 socklen_t sockaddr_size = sizeof(sock_addr); 284 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) == 0) { 285 return TRUE; 286 } 287 288 if (errno != ENOTCONN) { 289 return FALSE; 290 } 291 292 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) { 293 return FALSE; 294 } 295 } 296 } 297 298 bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout) 299 { 300 uint64_t stop_time = getcurrenttime() + timeout; 301 const uint8_t *ptr = (const uint8_t *)data; 302 303 while (1) { 304 int ret = send(sock, ptr, length, 0); 305 if (ret >= (int)length) { 306 return TRUE; 307 } 308 309 if (ret > 0) { 310 ptr += ret; 311 length -= ret; 312 } 313 314 if (errno == EINPROGRESS) { 315 errno = EWOULDBLOCK; 316 } 317 if (errno != EWOULDBLOCK) { 318 return FALSE; 319 } 320 321 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) { 322 return FALSE; 323 } 324 } 325 } 326 327 bool_t hdhomerun_sock_sendto(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout) 328 { 329 uint64_t stop_time = getcurrenttime() + timeout; 330 const uint8_t *ptr = (const uint8_t *)data; 331 332 while (1) { 333 struct sockaddr_in sock_addr; 334 memset(&sock_addr, 0, sizeof(sock_addr)); 335 sock_addr.sin_family = AF_INET; 336 sock_addr.sin_addr.s_addr = htonl(remote_addr); 337 sock_addr.sin_port = htons(remote_port); 338 339 int ret = sendto(sock, ptr, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); 340 if (ret >= (int)length) { 341 return TRUE; 342 } 343 344 if (ret > 0) { 345 ptr += ret; 346 length -= ret; 347 } 348 349 if (errno == EINPROGRESS) { 350 errno = EWOULDBLOCK; 351 } 352 if (errno != EWOULDBLOCK) { 353 return FALSE; 354 } 355 356 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) { 357 return FALSE; 358 } 359 } 360 } 361 362 bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout) 363 { 364 uint64_t stop_time = getcurrenttime() + timeout; 365 366 while (1) { 367 int ret = recv(sock, data, *length, 0); 368 if (ret > 0) { 369 *length = ret; 370 return TRUE; 371 } 372 373 if (errno == EINPROGRESS) { 374 errno = EWOULDBLOCK; 375 } 376 if (errno != EWOULDBLOCK) { 377 return FALSE; 378 } 379 380 if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) { 381 return FALSE; 382 } 383 } 384 } 385 386 bool_t hdhomerun_sock_recvfrom(hdhomerun_sock_t sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout) 387 { 388 uint64_t stop_time = getcurrenttime() + timeout; 389 390 while (1) { 391 struct sockaddr_in sock_addr; 392 memset(&sock_addr, 0, sizeof(sock_addr)); 393 socklen_t sockaddr_size = sizeof(sock_addr); 394 395 int ret = recvfrom(sock, data, *length, 0, (struct sockaddr *)&sock_addr, &sockaddr_size); 396 if (ret > 0) { 397 *remote_addr = ntohl(sock_addr.sin_addr.s_addr); 398 *remote_port = ntohs(sock_addr.sin_port); 399 *length = ret; 400 return TRUE; 401 } 402 403 if (errno == EINPROGRESS) { 404 errno = EWOULDBLOCK; 405 } 406 if (errno != EWOULDBLOCK) { 407 return FALSE; 408 } 409 410 if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) { 411 return FALSE; 412 } 413 } 414 }