Ticket #8387: libmythhdhomerun.patch

File libmythhdhomerun.patch, 129.0 KB (added by jafa@…, 14 years ago)

latest libhdhomerun

  • hdhomerun_control.h

     
    11/*
    22 * hdhomerun_control.h
    33 *
    4  * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
  • hdhomerun.h

     
    1 #ifndef __HDHOMERUN_INCLUDES__
    2 #define __HDHOMERUN_INCLUDES__
    31/*
    42 * hdhomerun.h
    53 *
    6  * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    75 *
    86 * This library is free software; you can redistribute it and/or
    97 * modify it under the terms of the GNU Lesser General Public
     
    3533#include "hdhomerun_os.h"
    3634#include "hdhomerun_types.h"
    3735#include "hdhomerun_pkt.h"
     36#include "hdhomerun_sock.h"
    3837#include "hdhomerun_debug.h"
    3938#include "hdhomerun_discover.h"
    4039#include "hdhomerun_control.h"
     
    4342#include "hdhomerun_channelscan.h"
    4443#include "hdhomerun_device.h"
    4544#include "hdhomerun_device_selector.h"
    46 
    47 #endif /* __HDHOMERUN_INCLUDES__ */
  • hdhomerun_debug.c

     
    11/*
    22 * hdhomerun_debug.c
    33 *
    4  * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    4444#define HDHOMERUN_DEBUG_HOST "debug.silicondust.com"
    4545#endif
    4646#if !defined(HDHOMERUN_DEBUG_PORT)
    47 #define HDHOMERUN_DEBUG_PORT "8002"
     47#define HDHOMERUN_DEBUG_PORT 8002
    4848#endif
    4949
     50#define HDHOMERUN_DEBUG_CONNECT_RETRY_TIME 30000
     51#define HDHOMERUN_DEBUG_CONNECT_TIMEOUT 10000
     52#define HDHOMERUN_DEBUG_SEND_TIMEOUT 10000
     53
    5054struct hdhomerun_debug_message_t
    5155{
    5256        struct hdhomerun_debug_message_t *next;
     
    7377
    7478        char *file_name;
    7579        FILE *file_fp;
    76         int sock;
     80        hdhomerun_sock_t sock;
    7781};
    7882
    7983static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg);
     
    8589                return NULL;
    8690        }
    8791
    88         dbg->sock = -1;
     92        dbg->sock = HDHOMERUN_SOCK_INVALID;
    8993
    9094        pthread_mutex_init(&dbg->print_lock, NULL);
    9195        pthread_mutex_init(&dbg->queue_lock, NULL);
     
    117121        if (dbg->file_fp) {
    118122                fclose(dbg->file_fp);
    119123        }
    120         if (dbg->sock != -1) {
    121                 close(dbg->sock);
     124        if (dbg->sock != HDHOMERUN_SOCK_INVALID) {
     125                hdhomerun_sock_destroy(dbg->sock);
    122126        }
    123127
    124128        free(dbg);
     
    132136                dbg->file_fp = NULL;
    133137        }
    134138
    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;
    138142        }
    139143}
    140144
     
    251255                        return;
    252256                }
    253257
    254                 msleep(10);
     258                msleep_approx(10);
    255259        }
    256260}
    257261
     
    372376}
    373377
    374378/* Send lock held by caller */
    375 #if defined(__CYGWIN__)
    376379static bool_t hdhomerun_debug_output_message_sock(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message)
    377380{
    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) {
    384382                uint64_t current_time = getcurrenttime();
    385383                if (current_time < dbg->connect_delay) {
    386384                        return FALSE;
    387385                }
    388                 dbg->connect_delay = current_time + 30*1000;
     386                dbg->connect_delay = current_time + HDHOMERUN_DEBUG_CONNECT_RETRY_TIME;
    389387
    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) {
    392390                        return FALSE;
    393391                }
    394392
    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) {
    403395                        hdhomerun_debug_close_internal(dbg);
    404396                        return FALSE;
    405397                }
    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)) {
    408400                        hdhomerun_debug_close_internal(dbg);
    409401                        return FALSE;
    410402                }
    411                 freeaddrinfo(sock_info);
    412403        }
    413404
    414405        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)) {
    416407                hdhomerun_debug_close_internal(dbg);
    417408                return FALSE;
    418409        }
    419410
    420411        return TRUE;
    421412}
    422 #endif
    423413
    424414static bool_t hdhomerun_debug_output_message(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message)
    425415{
     
    466456                pthread_mutex_unlock(&dbg->queue_lock);
    467457
    468458                if (!message) {
    469                         msleep(250);
     459                        msleep_approx(250);
    470460                        continue;
    471461                }
    472462
     
    476466                }
    477467
    478468                if (!hdhomerun_debug_output_message(dbg, message)) {
    479                         msleep(250);
     469                        msleep_approx(250);
    480470                        continue;
    481471                }
    482472
  • libmythhdhomerun.pro

     
    1010
    1111QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2)
    1212
    13 HEADERS += hdhomerun.h  hdhomerun_os.h  hdhomerun_types.h
     13HEADERS += hdhomerun.h  hdhomerun_os.h  hdhomerun_sock.h  hdhomerun_types.h
    1414
    1515HEADERS += hdhomerun_channels.h  hdhomerun_channelscan.h  hdhomerun_control.h
    16 HEADERS += hdhomerun_debug.h     hdhomerun_device.h       hdhomerun_dhcp.h
     16HEADERS += hdhomerun_debug.h     hdhomerun_device.h       hdhomerun_device_selector.h
    1717HEADERS += hdhomerun_discover.h  hdhomerun_pkt.h          hdhomerun_video.h
    18 HEADERS += hdhomerun_device_selector.h
    1918
    2019SOURCES += hdhomerun_channels.c  hdhomerun_channelscan.c  hdhomerun_control.c
    21 SOURCES += hdhomerun_debug.c     hdhomerun_device.c       hdhomerun_dhcp.c
     20SOURCES += hdhomerun_debug.c     hdhomerun_device.c       hdhomerun_device_selector.c
    2221SOURCES += hdhomerun_discover.c  hdhomerun_pkt.c          hdhomerun_video.c
    23 SOURCES += hdhomerun_device_selector.c
    2422
     23unix {
     24    HEADERS += hdhomerun_os_posix.h  hdhomerun_sock_posix.h
     25    SOURCES += hdhomerun_os_posix.c hdhomerun_sock_posix.c
     26}
     27
    2528mingw {
    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
    2731    LIBS += -lws2_32 -liphlpapi -lpthread
    2832}
    2933
  • hdhomerun_debug.h

     
    11/*
    22 * hdhomerun_debug.h
    33 *
    4  * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * 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
     35uint64_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
     63void 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
     77void 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
     33extern "C" {
     34#endif
     35
     36#define HDHOMERUN_SOCK_INVALID -1
     37
     38typedef int hdhomerun_sock_t;
     39
     40extern LIBTYPE hdhomerun_sock_t hdhomerun_sock_create_udp(void);
     41extern LIBTYPE hdhomerun_sock_t hdhomerun_sock_create_tcp(void);
     42extern LIBTYPE void hdhomerun_sock_destroy(hdhomerun_sock_t sock);
     43
     44extern LIBTYPE int hdhomerun_sock_getlasterror(void);
     45extern LIBTYPE uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock);
     46extern LIBTYPE uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock);
     47extern LIBTYPE uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock);
     48extern LIBTYPE uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name);
     49
     50extern LIBTYPE bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port);
     51extern LIBTYPE bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout);
     52
     53extern LIBTYPE bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout);
     54extern 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
     56extern LIBTYPE bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout);
     57extern 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
       + *
    
     
    11/*
    22 * hdhomerun_config.c
    33 *
    4  * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    202202        return cmd_set_internal(item, value);
    203203}
    204204
    205 static bool_t sigabort = FALSE;
     205static volatile sig_atomic_t sigabort_flag = FALSE;
     206static volatile sig_atomic_t siginfo_flag = FALSE;
     207 
     208static void sigabort_handler(int arg)
     209{
     210        sigabort_flag = TRUE;
     211}
    206212
    207 static void signal_abort(int arg)
     213static void siginfo_handler(int arg)
    208214{
    209         sigabort = TRUE;
     215        siginfo_flag = TRUE;
    210216}
    211217
     218static 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
    212231static void cmd_scan_printf(FILE *fp, const char *fmt, ...)
    213232{
    214233        va_list ap;
     
    274293                }
    275294        }
    276295
    277         signal(SIGINT, signal_abort);
    278         signal(SIGPIPE, signal_abort);
     296        register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler);
    279297
    280298        int ret = 0;
    281         while (!sigabort) {
     299        while (!sigabort_flag) {
    282300                struct hdhomerun_channelscan_result_t result;
    283301                ret = hdhomerun_device_channelscan_advance(hd, &result);
    284302                if (ret <= 0) {
     
    286304                }
    287305
    288306                cmd_scan_printf(fp, "SCANNING: %lu (%s)\n",
    289                         result.frequency, result.channel_str
     307                        (unsigned long)result.frequency, result.channel_str
    290308                );
    291309
    292310                ret = hdhomerun_device_channelscan_detect(hd, &result);
     
    321339        return ret;
    322340}
    323341
     342static 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
    324356static int cmd_save(const char *tuner_str, const char *filename)
    325357{
    326358        if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) {
     
    350382                return ret;
    351383        }
    352384
    353         signal(SIGINT, signal_abort);
    354         signal(SIGPIPE, signal_abort);
     385        register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler);
    355386
    356387        struct hdhomerun_video_stats_t stats_old, stats_cur;
    357388        hdhomerun_device_get_video_stats(hd, &stats_old);
    358389
    359390        uint64_t next_progress = getcurrenttime() + 1000;
    360391
    361         while (!sigabort) {
     392        while (!sigabort_flag) {
    362393                uint64_t loop_start_time = getcurrenttime();
    363394
     395                if (siginfo_flag) {
     396                        fprintf(stderr, "\n");
     397                        cmd_save_print_stats();
     398                        siginfo_flag = FALSE;
     399                }
     400
    364401                size_t actual_size;
    365402                uint8_t *ptr = hdhomerun_device_stream_recv(hd, VIDEO_DATA_BUFFER_SIZE_1S, &actual_size);
    366403                if (!ptr) {
    367                         msleep(64);
     404                        msleep_approx(64);
    368405                        continue;
    369406                }
    370407
     
    381418                                next_progress = loop_start_time + 1000;
    382419                        }
    383420
     421                        /* Windows - indicate activity to suppress auto sleep mode. */
     422                        #if defined(__WINDOWS__)
     423                        SetThreadExecutionState(ES_SYSTEM_REQUIRED);
     424                        #endif
     425
     426                        /* Video stats. */
    384427                        hdhomerun_device_get_video_stats(hd, &stats_cur);
    385428
    386429                        if (stats_cur.overflow_error_count > stats_old.overflow_error_count) {
     
    404447                        continue;
    405448                }
    406449
    407                 msleep(delay);
     450                msleep_approx(delay);
    408451        }
    409452
    410453        if (fp) {
     
    412455        }
    413456
    414457        hdhomerun_device_stream_stop(hd);
    415         hdhomerun_device_get_video_stats(hd, &stats_cur);
    416458
    417459        fprintf(stderr, "\n");
    418460        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();
    425462
    426463        return 0;
    427464}
     
    440477                fclose(fp);
    441478                return -1;
    442479        }
    443         sleep(2);
     480        msleep_minimum(2000);
    444481
    445482        printf("upgrading firmware...\n");
    446         sleep(8);
     483        msleep_minimum(8000);
    447484
    448485        printf("rebooting...\n");
    449486        int count = 0;
     
    460497                        return -1;
    461498                }
    462499
    463                 sleep(1);
     500                msleep_minimum(1000);
    464501        }
    465502
    466503        printf("upgrade complete - now running firmware %s\n", version_str);
  • hdhomerun_video.c

     
    11/*
    22 * hdhomerun_video.c
    33 *
    4  * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    3434
    3535struct hdhomerun_video_sock_t {
    3636        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;
    3744        uint8_t *buffer;
    3845        size_t buffer_size;
    39         volatile size_t head;
    40         volatile size_t tail;
    4146        size_t advance;
     47
     48        pthread_t thread;
    4249        volatile bool_t terminate;
    43         pthread_t thread;
    44         int sock;
    45         uint32_t rtp_sequence;
    46         struct hdhomerun_debug_t *dbg;
     50
    4751        volatile uint32_t packet_count;
    4852        volatile uint32_t transport_error_count;
    4953        volatile uint32_t network_error_count;
    5054        volatile uint32_t sequence_error_count;
    5155        volatile uint32_t overflow_error_count;
     56
     57        volatile uint32_t rtp_sequence;
    5258        volatile uint8_t sequence[0x2000];
    5359};
    5460
     
    6470        }
    6571
    6672        vs->dbg = dbg;
    67         vs->sock = -1;
     73        vs->sock = HDHOMERUN_SOCK_INVALID;
    6874        pthread_mutex_init(&vs->lock, NULL);
    6975
    7076        /* Reset sequence tracking. */
     
    8692        }
    8793       
    8894        /* 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) {
    9197                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate socket\n");
    9298                goto error;
    9399        }
     
    96102        int rx_size = 1024 * 1024;
    97103        setsockopt(vs->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rx_size, sizeof(rx_size));
    98104
    99         /* Set timeouts. */
    100         setsocktimeout(vs->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
    101         setsocktimeout(vs->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
    102 
    103105        /* 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)) {
    110107                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to bind socket (port %u)\n", listen_port);
    111108                goto error;
    112109        }
     
    121118        return vs;
    122119
    123120error:
    124         if (vs->sock != -1) {
    125                 close(vs->sock);
     121        if (vs->sock != HDHOMERUN_SOCK_INVALID) {
     122                hdhomerun_sock_destroy(vs->sock);
    126123        }
    127124        if (vs->buffer) {
    128125                free(vs->buffer);
     
    136133        vs->terminate = TRUE;
    137134        pthread_join(vs->thread, NULL);
    138135
    139         close(vs->sock);
     136        hdhomerun_sock_destroy(vs->sock);
    140137        free(vs->buffer);
    141138
    142139        free(vs);
    143140}
    144141
     142hdhomerun_sock_t hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs)
     143{
     144        return vs->sock;
     145}
     146
    145147uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs)
    146148{
    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());
    151152                return 0;
    152153        }
    153154
    154         return ntohs(sock_addr.sin_port);
     155        return port;
    155156}
    156157
     158int 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
     178int 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
    157197static void hdhomerun_video_stats_ts_pkt(struct hdhomerun_video_sock_t *vs, uint8_t *ptr)
    158198{
    159199        uint16_t packet_identifier = ((uint16_t)(ptr[1] & 0x1F) << 8) | (uint16_t)ptr[2];
     
    168208                return;
    169209        }
    170210
    171         uint8_t continuity_counter = ptr[3] & 0x0F;
     211        uint8_t sequence = ptr[3] & 0x0F;
     212
    172213        uint8_t previous_sequence = vs->sequence[packet_identifier];
     214        vs->sequence[packet_identifier] = sequence;
    173215
    174         if (continuity_counter == ((previous_sequence + 1) & 0x0F)) {
    175                 vs->sequence[packet_identifier] = continuity_counter;
     216        if (previous_sequence == 0xFF) {
    176217                return;
    177218        }
    178         if (previous_sequence == 0xFF) {
    179                 vs->sequence[packet_identifier] = continuity_counter;
     219        if (sequence == ((previous_sequence + 1) & 0x0F)) {
    180220                return;
    181221        }
    182         if (continuity_counter == previous_sequence) {
     222        if (sequence == previous_sequence) {
    183223                return;
    184224        }
    185225
    186226        vs->sequence_error_count++;
    187         vs->sequence[packet_identifier] = continuity_counter;
    188227}
    189228
    190229static void hdhomerun_video_parse_rtp(struct hdhomerun_video_sock_t *vs, struct hdhomerun_pkt_t *pkt)
     
    193232        uint32_t rtp_sequence = hdhomerun_pkt_read_u16(pkt);
    194233        pkt->pos += 8;
    195234
    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;
    199237
    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;
    206241        }
    207242
    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        }
    209256}
    210257
    211258static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg)
     
    218265                hdhomerun_pkt_reset(pkt);
    219266
    220267                /* 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
    222273                pkt->end += length;
    223274
    224275                if (length == VIDEO_RTP_DATA_PACKET_SIZE) {
     
    227278                }
    228279
    229280                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;
    240283                }
    241284
    242285                pthread_mutex_lock(&vs->lock);
     
    269312                        continue;
    270313                }
    271314
    272                 /* Atomic update. */
    273315                vs->head = head;
    274316
    275317                pthread_mutex_unlock(&vs->lock);
     
    291333                        tail -= vs->buffer_size;
    292334                }
    293335       
    294                 /* Atomic update. */
    295336                vs->tail = tail;
    296337        }
    297338
     
    334375        vs->tail = vs->head;
    335376        vs->advance = 0;
    336377
    337         /* can't use memset bcs sequence is volatile */
     378        vs->rtp_sequence = 0xFFFFFFFF;
     379
    338380        int i;
    339         for (i = 0; i < sizeof(vs->sequence) / sizeof(uint8_t) ; i++)
     381        for (i = 0; i < 0x2000; i++) {
    340382                vs->sequence[i] = 0xFF;
     383        }
    341384
    342         vs->rtp_sequence = 0xFFFFFFFF;
    343 
    344385        vs->packet_count = 0;
    345386        vs->transport_error_count = 0;
    346387        vs->network_error_count = 0;
     
    355396        struct hdhomerun_video_stats_t stats;
    356397        hdhomerun_video_get_stats(vs, &stats);
    357398
    358         hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%ld 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_count
     399        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
    362403        );
    363404}
    364405
  • hdhomerun_os_posix.h

     
    11/*
    22 * hdhomerun_os_posix.h
    33 *
    4  * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    3838#include <unistd.h>
    3939#include <errno.h>
    4040#include <fcntl.h>
     41#include <signal.h>
    4142#include <sys/types.h>
    4243#include <sys/socket.h>
    4344#include <sys/time.h>
    4445#include <sys/timeb.h>
    4546#include <sys/wait.h>
    46 #include <sys/signal.h>
    4747#include <netinet/in.h>
    4848#include <arpa/inet.h>
    4949#include <netdb.h>
    5050#include <pthread.h>
    5151
    5252typedef int bool_t;
     53typedef void (*sig_t)(int);
    5354
    5455#define LIBTYPE
    55 #define sock_getlasterror errno
    56 #define sock_getlasterror_socktimeout (errno == EAGAIN)
    5756#define console_vprintf vprintf
    5857#define console_printf printf
    5958#define THREAD_FUNC_PREFIX void *
    6059
    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
     61extern "C" {
     62#endif
    6763
    68 static inline int msleep(unsigned int ms)
    69 {
    70         uint64_t stop_time = getcurrenttime() + ms;
     64extern LIBTYPE uint64_t getcurrenttime(void);
     65extern LIBTYPE void msleep_approx(uint64_t ms);
     66extern LIBTYPE void msleep_minimum(uint64_t ms);
    7167
    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
    8769}
    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
     50hdhomerun_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
     73hdhomerun_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
     92void hdhomerun_sock_destroy(hdhomerun_sock_t sock)
     93{
     94        closesocket(sock);
     95}
     96
     97int hdhomerun_sock_getlasterror(void)
     98{
     99        return WSAGetLastError();
     100}
     101
     102uint32_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
     114uint16_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
     126uint32_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
     138uint32_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
     158bool_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
     173bool_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
     216static 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
     243bool_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
     269bool_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
     301bool_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
     322bool_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
       + *
    
     
    11/*
    22 * hdhomerun_video.h
    33 *
    4  * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    7171extern LIBTYPE uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs);
    7272
    7373/*
     74 * Join/leave multicast group.
     75 */
     76extern LIBTYPE int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip);
     77extern LIBTYPE int hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs);
     78
     79/*
    7480 * Read data from buffer.
    7581 *
    7682 * size_t max_size: The maximum amount of data to be returned.
     
    100106extern LIBTYPE void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs);
    101107extern LIBTYPE void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomerun_video_stats_t *stats);
    102108
     109/*
     110 * Internal use only.
     111 */
     112extern LIBTYPE hdhomerun_sock_t hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs);
     113
    103114#ifdef __cplusplus
    104115}
    105116#endif
  • hdhomerun_channelscan.c

     
    11/*
    22 * hdhomerun_channelscan.c
    33 *
    4  * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2007-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    9999                        return 1;
    100100                }
    101101
    102                 msleep(250);
     102                msleep_approx(250);
    103103        }
    104104}
    105105
     
    303303                        break;
    304304                }
    305305
    306                 msleep(250);
     306                msleep_approx(250);
    307307        }
    308308
    309309        /* Lock => skip overlapping channels. */
  • hdhomerun_discover.c

     
    11/*
    22 * hdhomerun_discover.c
    33 *
    4  * Copyright © 2006-2007 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    4444#endif
    4545#endif
    4646
    47 #include <sys/param.h>  // Defines BSD on FreeBSD and Mac OS X
    48 #if defined(__linux__) || defined(__APPLE__) || defined(BSD)
    49 #  include <ifaddrs.h>
    50 #  define USE_IFADDRS 1
    51 #  include <sys/select.h>
    52 #endif
    53 
    5447#define HDHOMERUN_DISOCVER_MAX_SOCK_COUNT 16
    5548
    5649struct hdhomerun_discover_sock_t {
    57         int sock;
     50        hdhomerun_sock_t sock;
     51        bool_t detected;
    5852        uint32_t local_ip;
    5953        uint32_t subnet_mask;
    6054};
     
    6660        struct hdhomerun_pkt_t rx_pkt;
    6761};
    6862
    69 static bool_t hdhomerun_discover_sock_create(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
     63static bool_t hdhomerun_discover_sock_add(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
    7064{
     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
    7175        if (ds->sock_count >= HDHOMERUN_DISOCVER_MAX_SOCK_COUNT) {
    7276                return FALSE;
    7377        }
    7478
    7579        /* 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) {
    7882                return FALSE;
    7983        }
    8084
    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 
    8985        /* 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);
    9788                return FALSE;
    9889        }
    9990
    10091        /* Write sock entry. */
    10192        struct hdhomerun_discover_sock_t *dss = &ds->socks[ds->sock_count++];
    10293        dss->sock = sock;
     94        dss->detected = TRUE;
    10395        dss->local_ip = local_ip;
    10496        dss->subnet_mask = subnet_mask;
    10597
    10698        return TRUE;
    10799}
    108100
     101struct 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
     118void 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
    109129#if defined(USE_IPHLPAPI)
    110 static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
     130static void hdhomerun_discover_sock_detect_internal(struct hdhomerun_discover_t *ds)
    111131{
    112132        PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    113133        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
     
    138158                                continue;
    139159                        }
    140160
    141                         hdhomerun_discover_sock_create(ds, local_ip, mask);
     161                        hdhomerun_discover_sock_add(ds, local_ip, mask);
    142162                        pIPAddr = pIPAddr->Next;
    143163                }
    144164
     
    150170
    151171#else
    152172
    153 static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
     173static void hdhomerun_discover_sock_detect_internal(struct hdhomerun_discover_t *ds)
    154174{
    155         int fd = socket(AF_INET, SOCK_DGRAM, 0);
    156         if (fd == -1) {
    157                 return;
    158         }
     175        int sock = ds->socks[0].sock;
    159176
    160177        struct ifconf ifc;
    161178        uint8_t buf[8192];
     
    164181
    165182        memset(buf, 0, sizeof(buf));
    166183
    167         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
    168                 close(fd);
     184        if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) {
    169185                return;
    170186        }
    171187
     
    176192                struct ifreq *ifr = (struct ifreq *)ptr;
    177193                ptr += _SIZEOF_ADDR_IFREQ(*ifr);
    178194
    179                 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
     195                if (ioctl(sock, SIOCGIFADDR, ifr) != 0) {
    180196                        continue;
    181197                }
    182198                struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
     
    185201                        continue;
    186202                }
    187203
    188                 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
     204                if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) {
    189205                        continue;
    190206                }
    191207                struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
    192208                uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
    193209
    194                 hdhomerun_discover_sock_create(ds, local_ip, mask);
     210                hdhomerun_discover_sock_add(ds, local_ip, mask);
    195211        }
    196 
    197         close(fd);
    198212}
    199213#endif
    200214
    201 static struct hdhomerun_discover_t *hdhomerun_discover_create(void)
     215static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
    202216{
    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;
    206221        }
    207222
    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);
    213224
    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++;
    227240        }
    228241
    229         free(ds);
     242        ds->sock_count = count;
    230243}
    231244
    232245static 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)
     
    242255        hdhomerun_pkt_write_u32(tx_pkt, device_id);
    243256        hdhomerun_pkt_seal_frame(tx_pkt, HDHOMERUN_TYPE_DISCOVER_REQ);
    244257
    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);
    257259}
    258260
    259261static bool_t hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id)
     
    313315
    314316static bool_t hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id)
    315317{
    316         if (target_ip != 0) {
     318        if (target_ip == 0) {
     319                return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id);
     320        } else {
    317321                return hdhomerun_discover_send_target_ip(ds, target_ip, device_type, device_id);
    318322        }
    319 
    320         return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id);
    321323}
    322324
    323 static int hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result)
     325static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result)
    324326{
    325327        struct hdhomerun_pkt_t *rx_pkt = &ds->rx_pkt;
    326328        hdhomerun_pkt_reset(rx_pkt);
    327329
    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;
    336335        }
    337         rx_pkt->end += rx_length;
    338336
     337        rx_pkt->end += length;
     338
    339339        uint16_t type;
    340340        if (hdhomerun_pkt_open_frame(rx_pkt, &type) <= 0) {
    341                 return 0;
     341                return FALSE;
    342342        }
    343343        if (type != HDHOMERUN_TYPE_DISCOVER_RPY) {
    344                 return 0;
     344                return FALSE;
    345345        }
    346346
    347         result->ip_addr = ntohl(sock_addr.sin_addr.s_addr);
     347        result->ip_addr = remote_addr;
    348348        result->device_type = 0;
    349349        result->device_id = 0;
    350350
     
    378378                rx_pkt->pos = next;
    379379        }
    380380
    381         return 1;
     381        return TRUE;
    382382}
    383383
    384 static int hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result)
     384static bool_t hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result)
    385385{
    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 
    394386        unsigned int i;
    395387        for (i = 0; i < ds->sock_count; i++) {
    396388                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         }
    402389
    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;
    411392                }
    412 
    413                 if (hdhomerun_discover_recv_internal(ds, dss, result) <= 0) {
    414                         continue;
    415                 }
    416 
    417                 return 1;
    418393        }
    419394
    420         return 0;
     395        return FALSE;
    421396}
    422397
    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)
     398static 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)
    424399{
    425400        int index;
    426401        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;
    430405                }
    431406        }
    432407
    433408        return NULL;
    434409}
    435410
    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)
     411int 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)
    437412{
     413        hdhomerun_discover_sock_detect(ds);
     414
    438415        int count = 0;
    439416        int attempt;
    440417        for (attempt = 0; attempt < 2; attempt++) {
     
    443420                }
    444421
    445422                uint64_t timeout = getcurrenttime() + 200;
    446                 while (getcurrenttime() < timeout) {
     423                while (1) {
    447424                        struct hdhomerun_discover_device_t *result = &result_list[count];
    448425
    449                         int 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);
    454431                                continue;
    455432                        }
    456433
     
    467444                        }
    468445
    469446                        /* 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)) {
    471448                                continue;
    472449                        }
    473450
     
    484461
    485462int 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)
    486463{
     464        if (hdhomerun_discover_is_ip_multicast(target_ip)) {
     465                return 0;
     466        }
     467
    487468        struct hdhomerun_discover_t *ds = hdhomerun_discover_create();
    488469        if (!ds) {
    489470                return -1;
    490471        }
    491472
    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);
    493474
    494475        hdhomerun_discover_destroy(ds);
    495476        return ret;
     
    513494        return (checksum == 0);
    514495}
    515496
     497bool_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.c
    3  *
    4  * Copyright © 2006-2007 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.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 #else
    243                                sleep(1);
    244 #endif
    245                         }
    246                         continue;
    247                 }
    248                 pkt->end += rx_length;
    249 
    250                 hdhomerun_dhcp_recv(dhcp, pkt);
    251         }
    252 }
  • hdhomerun_channelscan.h

     
    11/*
    22 * hdhomerun_channelscan.h
    33 *
    4  * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
  • hdhomerun_dhcp.h

     
    1 /*
    2  * hdhomerun_dhcp.h
    3  *
    4  * Copyright © 2006 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 #ifdef __cplusplus
    34 extern "C" {
    35 #endif
    36 
    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 __cplusplus
    43 }
    44 #endif
  • hdhomerun_discover.h

     
    11/*
    22 * hdhomerun_discover.h
    33 *
    4  * Copyright © 2006-2007 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2007 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    4444 *
    4545 * The device information is stored in caller-supplied array of hdhomerun_discover_device_t vars.
    4646 * 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.
    4848 *
    4949 * Set target_ip to zero to auto-detect 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.
    5052 *
    5153 * Returns the number of devices found.
    5254 * Retruns -1 on error.
     
    5456extern 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);
    5557
    5658/*
     59 * Optional: persistent discover instance available for discover polling use.
     60 */
     61extern LIBTYPE struct hdhomerun_discover_t *hdhomerun_discover_create(void);
     62extern LIBTYPE void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds);
     63extern 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/*
    5766 * Verify that the device ID given is valid.
    5867 *
    5968 * The device ID contains a self-check sequence that detects common user input errors including
     
    6473 */
    6574extern LIBTYPE bool_t hdhomerun_discover_validate_device_id(uint32_t device_id);
    6675
     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 */
     82extern LIBTYPE bool_t hdhomerun_discover_is_ip_multicast(uint32_t ip_addr);
     83
    6784#ifdef __cplusplus
    6885}
    6986#endif
  • hdhomerun_os.h

     
    11/*
    22 * hdhomerun_os.h
    33 *
    4  * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
  • hdhomerun_channels.c

     
    11/*
    22 * hdhomerun_channels.c
    33 *
    4  * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * 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
     35uint64_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
     60void msleep_approx(uint64_t ms)
     61{
     62        Sleep((DWORD)ms);
     63}
     64
     65void 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
     79int 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
     88int 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
     101void pthread_mutex_init(pthread_mutex_t *mutex, void *attr)
     102{
     103        *mutex = CreateMutex(NULL, FALSE, NULL);
     104}
     105
     106void pthread_mutex_lock(pthread_mutex_t *mutex)
     107{
     108        WaitForSingleObject(*mutex, INFINITE);
     109}
     110
     111void 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 */
     121void 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
     129void 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_pkt.c

    Property changes on: hdhomerun_os_windows.c
    ___________________________________________________________________
    Added: svn:executable
       + *
    
     
    11/*
    22 * hdhomerun_pkt.c
    33 *
    4  * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
  • hdhomerun_device_selector.c

     
    11/*
    22 * hdhomerun_device_selector.c
    33 *
    4  * Copyright © 2009 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2009-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    6868        free(hds);
    6969}
    7070
     71LIBTYPE int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds)
     72{
     73        return (int)hds->hd_count;
     74}
     75
    7176void hdhomerun_device_selector_add_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd)
    7277{
    7378        size_t index;
     
    129134        return NULL;
    130135}
    131136
    132 void hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename)
     137int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename)
    133138{
    134139        FILE *fp = fopen(filename, "r");
    135140        if (!fp) {
    136                 return;
     141                return 0;
    137142        }
    138143
    139144        while(1) {
     
    151156        }
    152157
    153158        fclose(fp);
     159        return (int)hds->hd_count;
    154160}
    155161
    156162#if defined(__WINDOWS__)
    157 void hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource)
     163int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource)
    158164{
    159165        HKEY tuners_key;
    160166        LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Silicondust\\HDHomeRun\\Tuners", 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &tuners_key);
    161167        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;
    164170        }
    165171
    166172        DWORD index = 0;
     
    177183                HKEY device_key;
    178184                ret = RegOpenKeyEx(tuners_key, wdevice_name, 0, KEY_QUERY_VALUE, &device_key);
    179185                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);
    181187                        continue;
    182188                }
    183189
     
    207213        }
    208214
    209215        RegCloseKey(tuners_key);
     216        return (int)hds->hd_count;
    210217}
    211218#endif
    212219
     
    268275        /*
    269276         * Test local port.
    270277         */
    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) {
    273280                hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to create test sock\n", name);
    274281                return FALSE;
    275282        }
    276283
    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);
    284286
    285         if (ret != 0) {
     287        if (inuse) {
    286288                hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine\n", name);
    287289                return FALSE;
    288290        }
  • hdhomerun_device.c

     
    11/*
    22 * hdhomerun_device.c
    33 *
    4  * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    3737        struct hdhomerun_video_sock_t *vs;
    3838        struct hdhomerun_debug_t *dbg;
    3939        struct hdhomerun_channelscan_t *scan;
     40        uint32_t multicast_ip;
     41        uint16_t multicast_port;
    4042        uint32_t device_id;
    4143        unsigned int tuner;
    4244        uint32_t lockkey;
     
    4446        char model[32];
    4547};
    4648
    47 static void hdhomerun_device_set_update(struct hdhomerun_device_t *hd)
     49static int hdhomerun_device_set_device_normal(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip)
    4850{
    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        }
    5158
    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 {
    5859        hdhomerun_control_set_device(hd->cs, device_id, device_ip);
    5960
    6061        if ((device_id == 0) || (device_id == HDHOMERUN_DEVICE_ID_WILDCARD)) {
    6162                device_id = hdhomerun_control_get_device_id(hd->cs);
    6263        }
    6364
     65        hd->multicast_ip = 0;
     66        hd->multicast_port = 0;
    6467        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;
    6675}
    6776
    68 void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
     77static int hdhomerun_device_set_device_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip)
    6978{
     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
     97int 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
     111int 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
    70122        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;
    72126}
    73127
    74128struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg)
    75129{
    76130        struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)calloc(1, sizeof(struct hdhomerun_device_t));
    77131        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");
    79133                return NULL;
    80134        }
    81135
    82136        hd->dbg = dbg;
    83137
    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) {
    87143                free(hd);
    88144                return NULL;
    89145        }
     146        if (hdhomerun_device_set_tuner(hd, tuner) <= 0) {
     147                free(hd);
     148                return NULL;
     149        }
    90150
    91         hdhomerun_device_set_device(hd, device_id, device_ip);
    92         hdhomerun_device_set_tuner(hd, tuner);
    93 
    94151        return hd;
    95152}
    96153
     
    104161                hdhomerun_video_destroy(hd->vs);
    105162        }
    106163
    107         hdhomerun_control_destroy(hd->cs);
     164        if (hd->cs) {
     165                hdhomerun_control_destroy(hd->cs);
     166        }
    108167
    109168        free(hd);
    110169}
     
    156215static struct hdhomerun_device_t *hdhomerun_device_create_from_str_ip(const char *device_str, struct hdhomerun_debug_t *dbg)
    157216{
    158217        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) {
    163220                if (sscanf(device_str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) {
    164221                        return NULL;
    165222                }
    166223        }
    167224
    168225        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;
    170236}
    171237
    172238static struct hdhomerun_device_t *hdhomerun_device_create_from_str_dns(const char *device_str, struct hdhomerun_debug_t *dbg)
     
    239305
    240306uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd)
    241307{
    242         return hdhomerun_control_get_device_id(hd->cs);
     308        return hd->device_id;
    243309}
    244310
    245311uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd)
    246312{
    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;
    248321}
    249322
    250323uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd)
    251324{
    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;
    253333}
    254334
    255335uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd)
    256336{
    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;
    258345}
    259346
    260347unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd)
     
    273360                return hd->vs;
    274361        }
    275362
    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);
    277364        if (!hd->vs) {
    278365                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_video_sock: failed to create video object\n");
    279366                return NULL;
     
    284371
    285372uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd)
    286373{
    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;
    288379}
    289380
    290381static uint32_t hdhomerun_device_get_status_parse(const char *status_str, const char *tag)
     
    368459
    369460int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status)
    370461{
     462        if (!hd->cs) {
     463                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_status: device not set\n");
     464                return -1;
     465        }
     466
    371467        memset(status, 0, sizeof(struct hdhomerun_tuner_status_t));
    372468
    373469        char name[32];
     
    414510
    415511int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo)
    416512{
     513        if (!hd->cs) {
     514                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_streaminfo: device not set\n");
     515                return -1;
     516        }
     517
    417518        char name[32];
    418519        sprintf(name, "/tuner%u/streaminfo", hd->tuner);
    419520        return hdhomerun_control_get(hd->cs, name, pstreaminfo, NULL);
     
    421522
    422523int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel)
    423524{
     525        if (!hd->cs) {
     526                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_channel: device not set\n");
     527                return -1;
     528        }
     529
    424530        char name[32];
    425531        sprintf(name, "/tuner%u/channel", hd->tuner);
    426532        return hdhomerun_control_get(hd->cs, name, pchannel, NULL);
     
    428534
    429535int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap)
    430536{
     537        if (!hd->cs) {
     538                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_channelmap: device not set\n");
     539                return -1;
     540        }
     541
    431542        char name[32];
    432543        sprintf(name, "/tuner%u/channelmap", hd->tuner);
    433544        return hdhomerun_control_get(hd->cs, name, pchannelmap, NULL);
     
    435546
    436547int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter)
    437548{
     549        if (!hd->cs) {
     550                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_filter: device not set\n");
     551                return -1;
     552        }
     553
    438554        char name[32];
    439555        sprintf(name, "/tuner%u/filter", hd->tuner);
    440556        return hdhomerun_control_get(hd->cs, name, pfilter, NULL);
     
    442558
    443559int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram)
    444560{
     561        if (!hd->cs) {
     562                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_program: device not set\n");
     563                return -1;
     564        }
     565
    445566        char name[32];
    446567        sprintf(name, "/tuner%u/program", hd->tuner);
    447568        return hdhomerun_control_get(hd->cs, name, pprogram, NULL);
     
    449570
    450571int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget)
    451572{
     573        if (!hd->cs) {
     574                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_target: device not set\n");
     575                return -1;
     576        }
     577
    452578        char name[32];
    453579        sprintf(name, "/tuner%u/target", hd->tuner);
    454580        return hdhomerun_control_get(hd->cs, name, ptarget, NULL);
     
    456582
    457583int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount)
    458584{
     585        if (!hd->cs) {
     586                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_plotsample: device not set\n");
     587                return -1;
     588        }
     589
    459590        char name[32];
    460591        sprintf(name, "/tuner%u/plotsample", hd->tuner);
    461592
     
    505636
    506637int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner)
    507638{
     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
    508644        char name[32];
    509645        sprintf(name, "/tuner%u/lockkey", hd->tuner);
    510646        return hdhomerun_control_get(hd->cs, name, powner, NULL);
     
    512648
    513649int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget)
    514650{
     651        if (!hd->cs) {
     652                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_ir_target: device not set\n");
     653                return -1;
     654        }
     655
    515656        return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL);
    516657}
    517658
    518659int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation)
    519660{
     661        if (!hd->cs) {
     662                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_lineup_location: device not set\n");
     663                return -1;
     664        }
     665
    520666        return hdhomerun_control_get(hd->cs, "/lineup/location", plocation, NULL);
    521667}
    522668
    523669int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num)
    524670{
     671        if (!hd->cs) {
     672                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_version: device not set\n");
     673                return -1;
     674        }
     675
    525676        char *version_str;
    526677        int ret = hdhomerun_control_get(hd->cs, "/sys/version", &version_str, NULL);
    527678        if (ret <= 0) {
     
    546697
    547698int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel)
    548699{
     700        if (!hd->cs) {
     701                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channel: device not set\n");
     702                return -1;
     703        }
     704
    549705        char name[32];
    550706        sprintf(name, "/tuner%u/channel", hd->tuner);
    551707        return hdhomerun_control_set_with_lockkey(hd->cs, name, channel, hd->lockkey, NULL, NULL);
     
    553709
    554710int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap)
    555711{
     712        if (!hd->cs) {
     713                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channelmap: device not set\n");
     714                return -1;
     715        }
     716
    556717        char name[32];
    557718        sprintf(name, "/tuner%u/channelmap", hd->tuner);
    558719        return hdhomerun_control_set_with_lockkey(hd->cs, name, channelmap, hd->lockkey, NULL, NULL);
     
    560721
    561722int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter)
    562723{
     724        if (!hd->cs) {
     725                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_filter: device not set\n");
     726                return -1;
     727        }
     728
    563729        char name[32];
    564730        sprintf(name, "/tuner%u/filter", hd->tuner);
    565731        return hdhomerun_control_set_with_lockkey(hd->cs, name, filter, hd->lockkey, NULL, NULL);
     
    635801
    636802int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program)
    637803{
     804        if (!hd->cs) {
     805                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_program: device not set\n");
     806                return -1;
     807        }
     808
    638809        char name[32];
    639810        sprintf(name, "/tuner%u/program", hd->tuner);
    640811        return hdhomerun_control_set_with_lockkey(hd->cs, name, program, hd->lockkey, NULL, NULL);
     
    642813
    643814int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target)
    644815{
     816        if (!hd->cs) {
     817                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target: device not set\n");
     818                return -1;
     819        }
     820
    645821        char name[32];
    646822        sprintf(name, "/tuner%u/target", hd->tuner);
    647823        return hdhomerun_control_set_with_lockkey(hd->cs, name, target, hd->lockkey, NULL, NULL);
    648824}
    649825
    650 int hdhomerun_device_set_tuner_target_to_local_protocol(struct hdhomerun_device_t *hd, const char *protocol)
     826static int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd, const char *protocol)
    651827{
    652         /* Create video socket. */
    653         hdhomerun_device_get_video_sock(hd);
     828        if (!hd->cs) {
     829                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target_to_local: device not set\n");
     830                return -1;
     831        }
    654832        if (!hd->vs) {
     833                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target_to_local: video not initialized\n");
    655834                return -1;
    656835        }
    657836
     
    669848        return hdhomerun_device_set_tuner_target(hd, target);
    670849}
    671850
    672 int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd)
     851int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target)
    673852{
    674         return hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);
    675 }
     853        if (!hd->cs) {
     854                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_ir_target: device not set\n");
     855                return -1;
     856        }
    676857
    677 int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target)
    678 {
    679858        return hdhomerun_control_set(hd->cs, "/ir/target", target, NULL, NULL);
    680859}
    681860
    682861int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location)
    683862{
     863        if (!hd->cs) {
     864                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_lineup_location: device not set\n");
     865                return -1;
     866        }
     867
    684868        return hdhomerun_control_set(hd->cs, "/lineup/location", location, NULL, NULL);
    685869}
    686870
     871int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list)
     872{
     873        if (!hd->cs) {
     874                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_sys_dvbc_modulation: device not set\n");
     875                return -1;
     876        }
     877
     878        return hdhomerun_control_set(hd->cs, "/sys/dvbc_modulation", modulation_list, NULL, NULL);
     879}
     880
    687881int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror)
    688882{
     883        if (!hd->cs) {
     884                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_var: device not set\n");
     885                return -1;
     886        }
     887
    689888        return hdhomerun_control_get(hd->cs, name, pvalue, perror);
    690889}
    691890
    692891int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror)
    693892{
     893        if (!hd->cs) {
     894                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_var: device not set\n");
     895                return -1;
     896        }
     897
    694898        return hdhomerun_control_set_with_lockkey(hd->cs, name, value, hd->lockkey, pvalue, perror);
    695899}
    696900
    697901int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror)
    698902{
     903        if (hd->multicast_ip != 0) {
     904                return 1;
     905        }
     906        if (!hd->cs) {
     907                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_request: device not set\n");
     908                return -1;
     909        }
     910
    699911        uint32_t new_lockkey = (uint32_t)getcurrenttime();
    700912
    701913        char name[32];
     
    716928
    717929int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd)
    718930{
     931        if (hd->multicast_ip != 0) {
     932                return 1;
     933        }
     934        if (!hd->cs) {
     935                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_release: device not set\n");
     936                return -1;
     937        }
     938
    719939        if (hd->lockkey == 0) {
    720940                return 1;
    721941        }
     
    730950
    731951int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd)
    732952{
     953        if (hd->multicast_ip != 0) {
     954                return 1;
     955        }
     956        if (!hd->cs) {
     957                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_force: device not set\n");
     958                return -1;
     959        }
     960
    733961        char name[32];
    734962        sprintf(name, "/tuner%u/lockkey", hd->tuner);
    735963        int ret = hdhomerun_control_set(hd->cs, name, "force", NULL, NULL);
     
    740968
    741969void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey)
    742970{
     971        if (hd->multicast_ip != 0) {
     972                return;
     973        }
     974
    743975        hd->lockkey = lockkey;
    744976}
    745977
    746978int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status)
    747979{
    748980        /* Delay for SS reading to be valid (signal present). */
    749         msleep(250);
     981        msleep_minimum(250);
    750982
    751983        /* Wait for up to 2.5 seconds for lock. */
    752984        uint64_t timeout = getcurrenttime() + 2500;
     
    7681000                        return 1;
    7691001                }
    7701002
    771                 msleep(250);
     1003                msleep_approx(250);
    7721004        }
    7731005}
    7741006
    7751007int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
    7761008{
     1009        hdhomerun_device_get_video_sock(hd);
     1010        if (!hd->vs) {
     1011                return -1;
     1012        }
     1013
    7771014        /* Set target. */
    778         int ret = hdhomerun_device_stream_refresh_target(hd);
    779         if (ret <= 0) {
    780                 return ret;
     1015        if (hd->multicast_ip != 0) {
     1016                int ret = hdhomerun_video_join_multicast_group(hd->vs, hd->multicast_ip, 0);
     1017                if (ret <= 0) {
     1018                        return ret;
     1019                }
     1020        } else {
     1021                int ret = hdhomerun_device_set_tuner_target_to_local(hd, HDHOMERUN_TARGET_PROTOCOL_RTP);
     1022                if (ret == 0) {
     1023                        ret = hdhomerun_device_set_tuner_target_to_local(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);
     1024                }
     1025                if (ret <= 0) {
     1026                        return ret;
     1027                }
    7811028        }
    7821029
    7831030        /* Flush video buffer. */
    784         msleep(64);
     1031        msleep_minimum(64);
    7851032        hdhomerun_video_flush(hd->vs);
    7861033
    7871034        /* Success. */
    7881035        return 1;
    7891036}
    7901037
    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 
    8001038uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size)
    8011039{
    8021040        if (!hd->vs) {
     1041                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_recv: video not initialized\n");
    8031042                return NULL;
    8041043        }
     1044
    8051045        return hdhomerun_video_recv(hd->vs, max_size, pactual_size);
    8061046}
    8071047
    8081048void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd)
    8091049{
     1050        if (!hd->vs) {
     1051                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_flush: video not initialized\n");
     1052                return;
     1053        }
     1054
    8101055        hdhomerun_video_flush(hd->vs);
    8111056}
    8121057
    8131058void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd)
    8141059{
    815         hdhomerun_device_set_tuner_target(hd, "none");
     1060        if (!hd->vs) {
     1061                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_stop: video not initialized\n");
     1062                return;
     1063        }
     1064
     1065        if (hd->multicast_ip != 0) {
     1066                hdhomerun_video_leave_multicast_group(hd->vs);
     1067        } else {
     1068                hdhomerun_device_set_tuner_target(hd, "none");
     1069        }
    8161070}
    8171071
    8181072int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap)
     
    8231077
    8241078        hd->scan = channelscan_create(hd, channelmap);
    8251079        if (!hd->scan) {
     1080                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_init: failed to create scan object\n");
    8261081                return -1;
    8271082        }
    8281083
     
    8321087int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
    8331088{
    8341089        if (!hd->scan) {
     1090                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_advance: scan not initialized\n");
    8351091                return 0;
    8361092        }
    8371093
     
    8471103int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
    8481104{
    8491105        if (!hd->scan) {
     1106                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_detect: scan not initialized\n");
    8501107                return 0;
    8511108        }
    8521109
     
    8621119uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd)
    8631120{
    8641121        if (!hd->scan) {
     1122                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_get_progress: scan not initialized\n");
    8651123                return 0;
    8661124        }
    8671125
    8681126        return channelscan_get_progress(hd->scan);
    8691127}
    8701128
    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 
    8851129const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd)
    8861130{
    8871131        if (*hd->model) {
    8881132                return hd->model;
    8891133        }
    8901134
     1135        if (!hd->cs) {
     1136                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_model_str: device not set\n");
     1137                return NULL;
     1138        }
     1139
    8911140        char *model_str;
    8921141        int ret = hdhomerun_control_get(hd->cs, "/sys/model", &model_str, NULL);
    8931142        if (ret < 0) {
    8941143                return NULL;
    8951144        }
    8961145        if (ret == 0) {
    897                 strncpy(hd->model, "hdhomerun_atsc", sizeof(hd->model) - 1);
    898                 hd->model[sizeof(hd->model) - 1] = 0;
     1146                model_str = "hdhomerun_atsc";
    8991147        }
    900         else
    901         {
    902                 strncpy(hd->model, model_str, sizeof(hd->model) - 1);
    903                 hd->model[sizeof(hd->model) - 1] = 0;
    904         }
    9051148
     1149        strncpy(hd->model, model_str, sizeof(hd->model) - 1);
     1150        hd->model[sizeof(hd->model) - 1] = 0;
     1151
    9061152        return hd->model;
    9071153}
    9081154
    9091155int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file)
    9101156{
     1157        if (!hd->cs) {
     1158                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_upgrade: device not set\n");
     1159                return -1;
     1160        }
     1161
    9111162        hdhomerun_control_set(hd->cs, "/tuner0/lockkey", "force", NULL, NULL);
    9121163        hdhomerun_control_set(hd->cs, "/tuner0/channel", "none", NULL, NULL);
    9131164
     
    9231174                return;
    9241175        }
    9251176
    926         char name[32];
    927         sprintf(name, "/tuner%u/debug", hd->tuner);
     1177        if (hd->cs) {
     1178                char name[32];
     1179                sprintf(name, "/tuner%u/debug", hd->tuner);
    9281180
    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         }
     1181                char *debug_str;
     1182                char *error_str;
     1183                int ret = hdhomerun_control_get(hd->cs, name, &debug_str, &error_str);
     1184                if (ret < 0) {
     1185                        hdhomerun_debug_printf(hd->dbg, "video dev: communication error getting debug stats\n");
     1186                        return;
     1187                }
    9361188
    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);
     1189                if (error_str) {
     1190                        hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", error_str);
     1191                } else {
     1192                        hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", debug_str);
     1193                }
    9411194        }
    9421195
    9431196        if (hd->vs) {
     
    9471200
    9481201void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats)
    9491202{
     1203        if (!hd->vs) {
     1204                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_flush: video not initialized\n");
     1205                memset(stats, 0, sizeof(struct hdhomerun_video_stats_t));
     1206                return;
     1207        }
     1208
    9501209        hdhomerun_video_get_stats(hd->vs, stats);
    9511210}
  • hdhomerun_channels.h

     
    11/*
    22 * hdhomerun_channels.h
    33 *
    4  * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2007-2008 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
  • hdhomerun_os_windows.h

     
    11/*
    22 * hdhomerun_os_windows.h
    33 *
    4  * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    3131 */
    3232
    3333#define _WINSOCKAPI_
    34 // MinGW lacks wspiapi, so remove dependency by setting minimum WINVER to WinXP
    35 #define WINVER 0x0501
    3634#include <windows.h>
    3735#include <winsock2.h>
    3836#include <ws2tcpip.h>
    39 //#include <wspiapi.h>
     37#include <wspiapi.h>
    4038#include <stdlib.h>
    4139#include <stdio.h>
    4240#include <stdarg.h>
     
    5553#endif
    5654
    5755typedef int bool_t;
    58 /* Use MinGW includes instead
    5956typedef signed __int8 int8_t;
    6057typedef signed __int16 int16_t;
    6158typedef signed __int32 int32_t;
     
    6461typedef unsigned __int16 uint16_t;
    6562typedef unsigned __int32 uint32_t;
    6663typedef unsigned __int64 uint64_t;
     64typedef void (*sig_t)(int);
    6765typedef HANDLE pthread_t;
    6866typedef HANDLE pthread_mutex_t;
    69 */
    70 #include <stdint.h>
    71 #include <pthread.h>
    7267
    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
    8069#define atoll _atoi64
    8170#define strdup _strdup
    8271#define strcasecmp _stricmp
     
    8473#define fseeko _fseeki64
    8574#define ftello _ftelli64
    8675#define THREAD_FUNC_PREFIX DWORD WINAPI
    87 #define SIGPIPE SIGABRT
     76
     77#ifdef __cplusplus
     78extern "C" {
    8879#endif
    8980
    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 }
     81extern LIBTYPE uint64_t getcurrenttime(void);
     82extern LIBTYPE void msleep_approx(uint64_t ms);
     83extern LIBTYPE void msleep_minimum(uint64_t ms);
    9684
    97 static inline int msleep(unsigned int ms)
    98 {
    99         uint64_t stop_time = getcurrenttime() + ms;
     85extern LIBTYPE int pthread_create(pthread_t *tid, void *attr, LPTHREAD_START_ROUTINE start, void *arg);
     86extern LIBTYPE int pthread_join(pthread_t tid, void **value_ptr);
     87extern LIBTYPE void pthread_mutex_init(pthread_mutex_t *mutex, void *attr);
     88extern LIBTYPE void pthread_mutex_lock(pthread_mutex_t *mutex);
     89extern LIBTYPE void pthread_mutex_unlock(pthread_mutex_t *mutex);
    10090
    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 conflict
    113 /*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 instead
    127 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 
    16591/*
    16692 * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing.
    16793 * Attempting to restore on exit fails to restore if the program is terminated by the user.
    16894 * Solution - set the output format each printf.
    16995 */
    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 }
     96extern LIBTYPE void console_vprintf(const char *fmt, va_list ap);
     97extern LIBTYPE void console_printf(const char *fmt, ...);
    17798
    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
    184100}
     101#endif
  • hdhomerun_pkt.h

     
    11/*
    22 * hdhomerun_pkt.h
    33 *
    4  * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2005-2006 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
  • hdhomerun_device.h

     
    11/*
    22 * hdhomerun_device.h
    33 *
    4  * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    5151 * GUI feedback to the user of the selected tuner might use 5 device objects: 4 for streaming video
    5252 * (one per thread) and one for the GUI display that can switch between tuners.
    5353 *
    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.
    5655 *
    5756 * uint32_t device_id = 32-bit device id of device. Set to HDHOMERUN_DEVICE_ID_WILDCARD to match any device ID.
    5857 * uint32_t device_ip = IP address of device. Set to 0 to auto-detect.
     
    6867 *     <device id>
    6968 *     <device id>-<tuner index>
    7069 *     <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_tuner or 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.
    7372 *
    7473 * The hdhomerun_device_set_tuner_from_str function sets the tuner from the given tuner_str.
    7574 * The tuner_str parameter can be any of the following forms:
     
    9089extern LIBTYPE uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd);
    9190extern LIBTYPE unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd);
    9291
    93 extern LIBTYPE void hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip);
    94 extern LIBTYPE void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);
     92extern LIBTYPE int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip);
     93extern LIBTYPE int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);
    9594extern LIBTYPE int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str);
    9695
    9796/*
     
    148147extern LIBTYPE int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000]);
    149148extern LIBTYPE int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program);
    150149extern 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);
    153150extern LIBTYPE int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target);
    154151extern LIBTYPE int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location);
     152extern LIBTYPE int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list);
    155153
    156154/*
    157155 * Get/set a named control variable on the device.
     
    224222 * The hdhomerun_device_stream_stop function tells the device to stop streaming data.
    225223 */
    226224extern 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);
    228225extern LIBTYPE uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size);
    229226extern LIBTYPE void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd);
    230227extern LIBTYPE void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd);
     
    238235extern LIBTYPE uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd);
    239236
    240237/*
    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 /*
    252238 * Upload new firmware to the device.
    253239 *
    254240 * FILE *upgrade_file: File pointer to read from. The file must have been opened in binary mode for reading.
  • hdhomerun_device_selector.h

     
    4343extern LIBTYPE void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, bool_t destroy_devices);
    4444
    4545/*
     46 * Get the number of devices in the list.
     47 */
     48extern LIBTYPE int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds);
     49
     50/*
    4651 * Populate device selector with devices from given source.
     52 * Returns the number of devices populated.
    4753 */
    48 extern LIBTYPE void hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename);
     54extern LIBTYPE int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename);
    4955#if defined(__WINDOWS__)
    50 extern LIBTYPE void hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource);
     56extern LIBTYPE int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource);
    5157#endif
    5258
    5359/*
  • hdhomerun_types.h

     
    11/*
    22 * hdhomerun_types.h
    33 *
    4  * Copyright © 2008-2009 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2008-2009 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
  • hdhomerun_control.c

     
    11/*
    22 * hdhomerun_control.c
    33 *
    4  * Copyright © 2006 Silicondust USA Inc. <www.silicondust.com>.
     4 * Copyright © 2006-2010 Silicondust USA Inc. <www.silicondust.com>.
    55 *
    66 * This library is free software; you can redistribute it and/or
    77 * modify it under the terms of the GNU Lesser General Public
     
    3232
    3333#include "hdhomerun.h"
    3434
    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
    3738#define HDHOMERUN_CONTROL_UPGRADE_TIMEOUT 20000
    3839
    3940struct hdhomerun_control_sock_t {
     
    4142        uint32_t desired_device_ip;
    4243        uint32_t actual_device_id;
    4344        uint32_t actual_device_ip;
    44         int sock;
     45        hdhomerun_sock_t sock;
    4546        struct hdhomerun_debug_t *dbg;
    4647        struct hdhomerun_pkt_t tx_pkt;
    4748        struct hdhomerun_pkt_t rx_pkt;
     
    4950
    5051static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs)
    5152{
    52         if (cs->sock == -1) {
     53        if (cs->sock == HDHOMERUN_SOCK_INVALID) {
    5354                return;
    5455        }
    5556
    56         close(cs->sock);
    57         cs->sock = -1;
     57        hdhomerun_sock_destroy(cs->sock);
     58        cs->sock = HDHOMERUN_SOCK_INVALID;
    5859}
    5960
    6061void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip)
     
    7677        }
    7778
    7879        cs->dbg = dbg;
    79         cs->sock = -1;
     80        cs->sock = HDHOMERUN_SOCK_INVALID;
    8081        hdhomerun_control_set_device(cs, device_id, device_ip);
    8182
    8283        return cs;
     
    9091
    9192static bool_t hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs)
    9293{
    93         if (cs->sock != -1) {
     94        if (cs->sock != HDHOMERUN_SOCK_INVALID) {
    9495                return TRUE;
    9596        }
    9697
     
    9899                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: no device specified\n");
    99100                return FALSE;
    100101        }
     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        }
    101106
    102107        /* Find device. */
    103108        struct hdhomerun_discover_device_t result;
     
    109114        cs->actual_device_id = result.device_id;
    110115
    111116        /* 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());
    115120                return FALSE;
    116121        }
    117122
    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 
    122123        /* 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());
    130126                hdhomerun_control_close_sock(cs);
    131127                return FALSE;
    132128        }
     
    172168                return 0;
    173169        }
    174170
    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());
    179174                return 0;
    180175        }
    181176
    182         return ntohl(sock_addr.sin_addr.s_addr);
     177        return addr;
    183178}
    184179
    185 static int hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt)
     180static bool_t hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt)
    186181{
    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());
    190184                hdhomerun_control_close_sock(cs);
    191                 return -1;
     185                return FALSE;
    192186        }
    193187
    194         return 1;
     188        return TRUE;
    195189}
    196190
    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)
     191static 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)
    198192{
    199193        uint64_t stop_time = getcurrenttime() + recv_timeout;
    200194        hdhomerun_pkt_reset(rx_pkt);
    201195
    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");
    213200                        hdhomerun_control_close_sock(cs);
    214                         return -1;
     201                        return FALSE;
    215202                }
    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());
    224207                        hdhomerun_control_close_sock(cs);
    225                         return -1;
     208                        return FALSE;
    226209                }
    227                 rx_pkt->end += rx_length;
    228210
     211                rx_pkt->end += length;
     212
    229213                int ret = hdhomerun_pkt_open_frame(rx_pkt, ptype);
    230214                if (ret < 0) {
    231215                        hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: frame error\n");
    232216                        hdhomerun_control_close_sock(cs);
    233                         return -1;
     217                        return FALSE;
    234218                }
    235                 if (ret == 0) {
    236                         continue;
     219                if (ret > 0) {
     220                        return TRUE;
    237221                }
    238 
    239                 return 1;
    240222        }
    241 
    242         hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: timeout\n");
    243         hdhomerun_control_close_sock(cs);
    244         return -1;
    245223}
    246224
    247225static 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)
     
    250228
    251229        int i;
    252230        for (i = 0; i < 2; i++) {
    253                 if (cs->sock == -1) {
     231                if (cs->sock == HDHOMERUN_SOCK_INVALID) {
    254232                        if (!hdhomerun_control_connect_sock(cs)) {
    255233                                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_recv: connect failed\n");
    256234                                return -1;
    257235                        }
    258236                }
    259237
    260                 if (hdhomerun_control_send_sock(cs, tx_pkt) < 0) {
     238                if (!hdhomerun_control_send_sock(cs, tx_pkt)) {
    261239                        continue;
    262240                }
    263241                if (!rx_pkt) {
     
    265243                }
    266244
    267245                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)) {
    269247                        continue;
    270248                }
    271249                if (rsp_type != type + 1) {
     
    301279        }
    302280        hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_GETSET_NAME);
    303281        hdhomerun_pkt_write_var_length(tx_pkt, name_len);
    304         hdhomerun_pkt_write_mem(tx_pkt, (const void *)name, name_len);
     282        hdhomerun_pkt_write_mem(tx_pkt, (void *)name, name_len);
    305283
    306284        if (value) {
    307285                int value_len = (int)strlen(value) + 1;
     
    311289                }
    312290                hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_GETSET_VALUE);
    313291                hdhomerun_pkt_write_var_length(tx_pkt, value_len);
    314                 hdhomerun_pkt_write_mem(tx_pkt, (const void *)value, value_len);
     292                hdhomerun_pkt_write_mem(tx_pkt, (void *)value, value_len);
    315293        }
    316294
    317295        if (lockkey != 0) {
  • 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
     51hdhomerun_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
     73hdhomerun_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
     91void hdhomerun_sock_destroy(hdhomerun_sock_t sock)
     92{
     93        close(sock);
     94}
     95
     96int hdhomerun_sock_getlasterror(void)
     97{
     98        return errno;
     99}
     100
     101uint32_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
     113uint16_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
     125uint32_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__)
     138uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name)
     139{
     140        return 0;
     141}
     142#else
     143uint32_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
     164bool_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
     179static 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
     218static 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
     257bool_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
     298bool_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 = (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
     327bool_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 = (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
     362bool_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
     386bool_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}