From 2f567a7aedb26ec2638cb14c87db2fefd0e439eb Mon Sep 17 00:00:00 2001 From: Patrick Hampson Date: Tue, 14 Nov 2017 00:28:05 -0500 Subject: [PATCH] Upgrade libhdhomerun + visual studio project version --- .gitignore | 3 +- HDHR.cpp | 2 +- HDHR.sln | 11 +- HDHR.vcxproj | 132 +++++ HDHR.vcxproj.filters | 114 +++++ libhdhomerun/hdhomerun.h | 20 +- libhdhomerun/hdhomerun_channels.c | 155 +++--- libhdhomerun/hdhomerun_channels.h | 55 +- libhdhomerun/hdhomerun_channelscan.c | 75 ++- libhdhomerun/hdhomerun_channelscan.h | 32 +- libhdhomerun/hdhomerun_config.c | 86 ++-- libhdhomerun/hdhomerun_control.c | 94 ++-- libhdhomerun/hdhomerun_control.h | 48 +- libhdhomerun/hdhomerun_debug.c | 227 ++++----- libhdhomerun/hdhomerun_debug.h | 44 +- libhdhomerun/hdhomerun_device.c | 609 ++++++++++++++--------- libhdhomerun/hdhomerun_device.h | 146 +++--- libhdhomerun/hdhomerun_device_selector.c | 247 ++++++--- libhdhomerun/hdhomerun_device_selector.h | 44 +- libhdhomerun/hdhomerun_discover.c | 322 ++++++------ libhdhomerun/hdhomerun_discover.h | 46 +- libhdhomerun/hdhomerun_os.h | 36 +- libhdhomerun/hdhomerun_os_posix.c | 262 ++++++++++ libhdhomerun/hdhomerun_os_posix.h | 84 ++++ libhdhomerun/hdhomerun_os_windows.c | 179 ++++--- libhdhomerun/hdhomerun_os_windows.h | 112 +++-- libhdhomerun/hdhomerun_pkt.c | 28 +- libhdhomerun/hdhomerun_pkt.h | 58 +-- libhdhomerun/hdhomerun_sock.h | 67 +-- libhdhomerun/hdhomerun_sock_posix.c | 544 ++++++++++++++++++++ libhdhomerun/hdhomerun_sock_windows.c | 532 +++++++++++++------- libhdhomerun/hdhomerun_types.h | 43 +- libhdhomerun/hdhomerun_video.c | 184 +++---- libhdhomerun/hdhomerun_video.h | 47 +- 34 files changed, 3075 insertions(+), 1613 deletions(-) create mode 100644 HDHR.vcxproj create mode 100644 HDHR.vcxproj.filters create mode 100644 libhdhomerun/hdhomerun_os_posix.c create mode 100644 libhdhomerun/hdhomerun_os_posix.h create mode 100644 libhdhomerun/hdhomerun_sock_posix.c diff --git a/.gitignore b/.gitignore index f58ad5f..fe6b87e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ Debug Release *.user *.ncb -*.suo \ No newline at end of file +*.suo +.vs/ \ No newline at end of file diff --git a/HDHR.cpp b/HDHR.cpp index dee1eaf..5944aff 100644 --- a/HDHR.cpp +++ b/HDHR.cpp @@ -49,7 +49,7 @@ public ref class HDHomeRun hd = hdhomerun_device_create_from_str(static_cast(p.ToPointer()), NULL); Marshal::FreeHGlobal(p); uint32_t id = ::hdhomerun_device_get_device_id_requested(hd); - bool_t valid = ::hdhomerun_discover_validate_device_id(id); + bool valid = ::hdhomerun_discover_validate_device_id(id); } diff --git a/HDHR.sln b/HDHR.sln index 1ac2d1d..87adfc5 100644 --- a/HDHR.sln +++ b/HDHR.sln @@ -1,7 +1,9 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HDHR", "HDHR.vcproj", "{B7B17717-DA85-49FA-882A-3950C1CD4471}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2008 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HDHR", "HDHR.vcxproj", "{B7B17717-DA85-49FA-882A-3950C1CD4471}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,4 +19,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8672F0F2-BB2A-4288-811A-C645BCE65907} + EndGlobalSection EndGlobal diff --git a/HDHR.vcxproj b/HDHR.vcxproj new file mode 100644 index 0000000..6d7adce --- /dev/null +++ b/HDHR.vcxproj @@ -0,0 +1,132 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {B7B17717-DA85-49FA-882A-3950C1CD4471} + HDHR + ManagedCProj + + + + Application + v141 + Unicode + true + true + + + DynamicLibrary + v141 + Unicode + true + + + + + + + + + + + + + <_ProjectFileVersion>15.0.26919.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + ./libhdhomerun;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + CompileAsCpp + + + ws2_32.lib;advapi32.lib;user32.lib;Iphlpapi.lib + true + true + MachineX86 + + + + + ./libhdhomerun;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + CompileAsCpp + + + ws2_32.lib;advapi32.lib;user32.lib;Iphlpapi.lib + true + MachineX86 + + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HDHR.vcxproj.filters b/HDHR.vcxproj.filters new file mode 100644 index 0000000..bab950b --- /dev/null +++ b/HDHR.vcxproj.filters @@ -0,0 +1,114 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {58bb5678-7ad1-4d0c-8cbb-cf1de67c1d9d} + + + + + Source Files + + + Source Files + + + Source Files + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + + + Header Files + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + libhdhomerun + + + + + + \ No newline at end of file diff --git a/libhdhomerun/hdhomerun.h b/libhdhomerun/hdhomerun.h index affd4e2..dd287ee 100644 --- a/libhdhomerun/hdhomerun.h +++ b/libhdhomerun/hdhomerun.h @@ -3,10 +3,10 @@ * * Copyright © 2006-2010 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun_os.h" diff --git a/libhdhomerun/hdhomerun_channels.c b/libhdhomerun/hdhomerun_channels.c index d112ee9..9db637e 100644 --- a/libhdhomerun/hdhomerun_channels.c +++ b/libhdhomerun/hdhomerun_channels.c @@ -1,12 +1,12 @@ /* * hdhomerun_channels.c * - * Copyright © 2007-2008 Silicondust USA Inc. . + * Copyright © 2007-2014 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,31 +14,17 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" -#define FREQUENCY_RESOLUTION 62500 - struct hdhomerun_channel_entry_t { struct hdhomerun_channel_entry_t *next; struct hdhomerun_channel_entry_t *prev; uint32_t frequency; - uint8_t channel_number; + uint16_t channel_number; char name[16]; }; @@ -48,8 +34,8 @@ struct hdhomerun_channel_list_t { }; struct hdhomerun_channelmap_range_t { - uint8_t channel_range_start; - uint8_t channel_range_end; + uint16_t channel_range_start; + uint16_t channel_range_end; uint32_t frequency; uint32_t spacing; }; @@ -61,32 +47,46 @@ struct hdhomerun_channelmap_record_t { const char *countrycodes; }; -/* AU antenna channels. Channels {0, 1, 2, 6, 7, 8, 9, 9A} are numbered {2, 3, 4, 5, 6, 7, 8, 9} by the HDHomeRun. */ +/* AU antenna channels. Channels {6, 7, 8, 9, 9A} are numbered {5, 6, 7, 8, 9} by the HDHomeRun. */ static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_au_bcast[] = { - { 2, 2, 48500000, 7000000}, - { 3, 4, 59500000, 7000000}, { 5, 12, 177500000, 7000000}, - { 28, 69, 529500000, 7000000}, - { 0, 0, 0, 0} -}; - -/* AU cable channels. TBD. */ -static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_au_cable[] = { + { 21, 69, 480500000, 7000000}, { 0, 0, 0, 0} }; /* EU antenna channels. */ static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_eu_bcast[] = { - { 2, 4, 50500000, 7000000}, { 5, 12, 177500000, 7000000}, { 21, 69, 474000000, 8000000}, { 0, 0, 0, 0} }; -/* EU cable channels. Channels do not have simple numbers - the HDHomeRun uses its own numbering scheme (subject to change). */ +/* EU cable channels. No common standard - use frequency in MHz for channel number. */ static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_eu_cable[] = { - { 6, 7, 113000000, 8000000}, - { 9, 100, 138000000, 8000000}, + {108, 862, 108000000, 1000000}, + { 0, 0, 0, 0} +}; + +/* KR cable channels. */ +static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_kr_cable[] = { + { 2, 4, 57000000, 6000000}, + { 5, 6, 79000000, 6000000}, + { 7, 13, 177000000, 6000000}, + { 14, 22, 123000000, 6000000}, + { 23, 153, 219000000, 6000000}, + { 0, 0, 0, 0} +}; + +/* JP antenna channels. */ +static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_jp_bcast[] = { + { 13, 62, 473000000, 6000000}, + { 0, 0, 0, 0} +}; + +/* TW antenna channels. */ +static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_tw_bcast[] = { + { 7, 13, 177000000, 6000000}, + { 14, 69, 473000000, 6000000}, { 0, 0, 0, 0} }; @@ -107,7 +107,7 @@ static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_c { 14, 22, 123000000, 6000000}, { 23, 94, 219000000, 6000000}, { 95, 99, 93000000, 6000000}, - {100, 135, 651000000, 6000000}, + {100, 158, 651000000, 6000000}, { 0, 0, 0, 0} }; @@ -119,7 +119,7 @@ static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_h { 14, 22, 121756000, 6000300}, { 23, 94, 217760800, 6000300}, { 95, 99, 91754500, 6000300}, - {100, 135, 649782400, 6000300}, + {100, 158, 649782400, 6000300}, { 0, 0, 0, 0} }; @@ -134,50 +134,65 @@ static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_i { 43, 94, 339012500, 6000000}, { 95, 97, 93012500, 6000000}, { 98, 99, 111025000, 6000000}, - {100, 135, 651012500, 6000000}, + {100, 158, 651012500, 6000000}, { 0, 0, 0, 0} }; static const struct hdhomerun_channelmap_record_t hdhomerun_channelmap_table[] = { {"au-bcast", hdhomerun_channelmap_range_au_bcast, "au-bcast", "AU"}, - {"au-cable", hdhomerun_channelmap_range_au_cable, "au-cable", "AU"}, - {"eu-bcast", hdhomerun_channelmap_range_eu_bcast, "eu-bcast", "EU PA"}, - {"eu-cable", hdhomerun_channelmap_range_eu_cable, "eu-cable", "EU"}, - {"tw-bcast", hdhomerun_channelmap_range_us_bcast, "tw-bcast", "TW"}, + {"au-cable", hdhomerun_channelmap_range_eu_cable, "au-cable", "AU"}, + {"eu-bcast", hdhomerun_channelmap_range_eu_bcast, "eu-bcast", NULL}, + {"eu-cable", hdhomerun_channelmap_range_eu_cable, "eu-cable", NULL}, + {"tw-bcast", hdhomerun_channelmap_range_tw_bcast, "tw-bcast", "TW"}, {"tw-cable", hdhomerun_channelmap_range_us_cable, "tw-cable", "TW"}, - {"us-bcast", hdhomerun_channelmap_range_us_bcast, "us-bcast", "CA US"}, - {"us-cable", hdhomerun_channelmap_range_us_cable, "us-cable us-hrc us-irc", "CA PA US"}, - {"us-hrc", hdhomerun_channelmap_range_us_hrc , "us-cable us-hrc us-irc", "CA PA US"}, - {"us-irc", hdhomerun_channelmap_range_us_irc, "us-cable us-hrc us-irc", "CA PA US"}, + {"kr-bcast", hdhomerun_channelmap_range_us_bcast, "kr-bcast", "KR"}, + {"kr-cable", hdhomerun_channelmap_range_kr_cable, "kr-cable", "KR"}, + {"us-bcast", hdhomerun_channelmap_range_us_bcast, "us-bcast", NULL}, + {"us-cable", hdhomerun_channelmap_range_us_cable, "us-cable us-hrc us-irc", NULL}, + {"us-hrc", hdhomerun_channelmap_range_us_hrc , "us-cable us-hrc us-irc", NULL}, + {"us-irc", hdhomerun_channelmap_range_us_irc, "us-cable us-hrc us-irc", NULL}, - {NULL, NULL, NULL, NULL} + {"jp-bcast", hdhomerun_channelmap_range_jp_bcast, "jp-bcast", "JP" }, + { NULL, NULL, NULL, NULL } }; -const char *hdhomerun_channelmap_get_channelmap_from_country_source(const char *countrycode, const char *source) +const char *hdhomerun_channelmap_get_channelmap_from_country_source(const char *countrycode, const char *source, const char *supported) { - bool_t country_found = FALSE; + const char *default_result = NULL; const struct hdhomerun_channelmap_record_t *record = hdhomerun_channelmap_table; while (record->channelmap) { - if (!strstr(record->countrycodes, countrycode)) { + /* Ignore records that do not match the requested source. */ + if (!strstr(record->channelmap, source)) { record++; continue; } - if (strstr(record->channelmap, source)) { - return record->channelmap; + /* Ignore records that are not supported by the hardware. */ + if (!strstr(supported, record->channelmap)) { + record++; + continue; } - country_found = TRUE; - record++; - } + /* If this record is the default result then remember it and keep searching. */ + if (!record->countrycodes) { + default_result = record->channelmap; + record++; + continue; + } - if (!country_found) { - return hdhomerun_channelmap_get_channelmap_from_country_source("EU", source); + /* Ignore records that have a countrycode filter and do not match. */ + if (!strstr(record->countrycodes, countrycode)) { + record++; + continue; + } + + /* Record found with exact match for source and countrycode. */ + return record->channelmap; } - return NULL; + return default_result; } const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelmap) @@ -193,7 +208,7 @@ const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelma return NULL; } -uint8_t hdhomerun_channel_entry_channel_number(struct hdhomerun_channel_entry_t *entry) +uint16_t hdhomerun_channel_entry_channel_number(struct hdhomerun_channel_entry_t *entry) { return entry->channel_number; } @@ -259,12 +274,18 @@ uint32_t hdhomerun_channel_list_frequency_count(struct hdhomerun_channel_list_t return count; } -uint32_t hdhomerun_channel_frequency_truncate(uint32_t frequency) +uint32_t hdhomerun_channel_frequency_round(uint32_t frequency, uint32_t resolution) +{ + frequency += resolution / 2; + return (frequency / resolution) * resolution; +} + +uint32_t hdhomerun_channel_frequency_round_normal(uint32_t frequency) { - return (frequency / FREQUENCY_RESOLUTION) * FREQUENCY_RESOLUTION; + return hdhomerun_channel_frequency_round(frequency, 125000); } -uint32_t hdhomerun_channel_number_to_frequency(struct hdhomerun_channel_list_t *channel_list, uint8_t channel_number) +uint32_t hdhomerun_channel_number_to_frequency(struct hdhomerun_channel_list_t *channel_list, uint16_t channel_number) { struct hdhomerun_channel_entry_t *entry = hdhomerun_channel_list_first(channel_list); while (entry) { @@ -278,9 +299,9 @@ uint32_t hdhomerun_channel_number_to_frequency(struct hdhomerun_channel_list_t * return 0; } -uint8_t hdhomerun_channel_frequency_to_number(struct hdhomerun_channel_list_t *channel_list, uint32_t frequency) +uint16_t hdhomerun_channel_frequency_to_number(struct hdhomerun_channel_list_t *channel_list, uint32_t frequency) { - frequency = hdhomerun_channel_frequency_truncate(frequency); + frequency = hdhomerun_channel_frequency_round_normal(frequency); struct hdhomerun_channel_entry_t *entry = hdhomerun_channel_list_first(channel_list); while (entry) { @@ -329,7 +350,7 @@ static void hdhomerun_channel_list_build_insert(struct hdhomerun_channel_list_t static void hdhomerun_channel_list_build_range(struct hdhomerun_channel_list_t *channel_list, const char *channelmap, const struct hdhomerun_channelmap_range_t *range) { - uint8_t channel_number; + uint16_t channel_number; for (channel_number = range->channel_range_start; channel_number <= range->channel_range_end; channel_number++) { struct hdhomerun_channel_entry_t *entry = (struct hdhomerun_channel_entry_t *)calloc(1, sizeof(struct hdhomerun_channel_entry_t)); if (!entry) { @@ -338,8 +359,8 @@ static void hdhomerun_channel_list_build_range(struct hdhomerun_channel_list_t * entry->channel_number = channel_number; entry->frequency = range->frequency + ((uint32_t)(channel_number - range->channel_range_start) * range->spacing); - entry->frequency = hdhomerun_channel_frequency_truncate(entry->frequency); - sprintf(entry->name, "%s:%u", channelmap, entry->channel_number); + entry->frequency = hdhomerun_channel_frequency_round_normal(entry->frequency); + hdhomerun_sprintf(entry->name, entry->name + sizeof(entry->name), "%s:%u", channelmap, entry->channel_number); hdhomerun_channel_list_build_insert(channel_list, entry); } diff --git a/libhdhomerun/hdhomerun_channels.h b/libhdhomerun/hdhomerun_channels.h index c67e8be..6061e88 100644 --- a/libhdhomerun/hdhomerun_channels.h +++ b/libhdhomerun/hdhomerun_channels.h @@ -1,12 +1,12 @@ /* * hdhomerun_channels.h * - * Copyright © 2007-2008 Silicondust USA Inc. . + * Copyright © 2007-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus @@ -37,26 +25,27 @@ extern "C" { struct hdhomerun_channel_entry_t; struct hdhomerun_channel_list_t; -extern LIBTYPE const char *hdhomerun_channelmap_get_channelmap_from_country_source(const char *countrycode, const char *source); -extern LIBTYPE const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelmap); +extern LIBHDHOMERUN_API const char *hdhomerun_channelmap_get_channelmap_from_country_source(const char *countrycode, const char *source, const char *supported); +extern LIBHDHOMERUN_API const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelmap); -extern LIBTYPE uint8_t hdhomerun_channel_entry_channel_number(struct hdhomerun_channel_entry_t *entry); -extern LIBTYPE uint32_t hdhomerun_channel_entry_frequency(struct hdhomerun_channel_entry_t *entry); -extern LIBTYPE const char *hdhomerun_channel_entry_name(struct hdhomerun_channel_entry_t *entry); +extern LIBHDHOMERUN_API uint16_t hdhomerun_channel_entry_channel_number(struct hdhomerun_channel_entry_t *entry); +extern LIBHDHOMERUN_API uint32_t hdhomerun_channel_entry_frequency(struct hdhomerun_channel_entry_t *entry); +extern LIBHDHOMERUN_API const char *hdhomerun_channel_entry_name(struct hdhomerun_channel_entry_t *entry); -extern LIBTYPE struct hdhomerun_channel_list_t *hdhomerun_channel_list_create(const char *channelmap); -extern LIBTYPE void hdhomerun_channel_list_destroy(struct hdhomerun_channel_list_t *channel_list); +extern LIBHDHOMERUN_API struct hdhomerun_channel_list_t *hdhomerun_channel_list_create(const char *channelmap); +extern LIBHDHOMERUN_API void hdhomerun_channel_list_destroy(struct hdhomerun_channel_list_t *channel_list); -extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_first(struct hdhomerun_channel_list_t *channel_list); -extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_last(struct hdhomerun_channel_list_t *channel_list); -extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_next(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry); -extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_prev(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry); -extern LIBTYPE uint32_t hdhomerun_channel_list_total_count(struct hdhomerun_channel_list_t *channel_list); -extern LIBTYPE uint32_t hdhomerun_channel_list_frequency_count(struct hdhomerun_channel_list_t *channel_list); +extern LIBHDHOMERUN_API struct hdhomerun_channel_entry_t *hdhomerun_channel_list_first(struct hdhomerun_channel_list_t *channel_list); +extern LIBHDHOMERUN_API struct hdhomerun_channel_entry_t *hdhomerun_channel_list_last(struct hdhomerun_channel_list_t *channel_list); +extern LIBHDHOMERUN_API struct hdhomerun_channel_entry_t *hdhomerun_channel_list_next(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry); +extern LIBHDHOMERUN_API struct hdhomerun_channel_entry_t *hdhomerun_channel_list_prev(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry); +extern LIBHDHOMERUN_API uint32_t hdhomerun_channel_list_total_count(struct hdhomerun_channel_list_t *channel_list); +extern LIBHDHOMERUN_API uint32_t hdhomerun_channel_list_frequency_count(struct hdhomerun_channel_list_t *channel_list); -extern LIBTYPE uint32_t hdhomerun_channel_frequency_truncate(uint32_t frequency); -extern LIBTYPE uint32_t hdhomerun_channel_number_to_frequency(struct hdhomerun_channel_list_t *channel_list, uint8_t channel_number); -extern LIBTYPE uint8_t hdhomerun_channel_frequency_to_number(struct hdhomerun_channel_list_t *channel_list, uint32_t frequency); +extern LIBHDHOMERUN_API uint32_t hdhomerun_channel_frequency_round(uint32_t frequency, uint32_t resolution); +extern LIBHDHOMERUN_API uint32_t hdhomerun_channel_frequency_round_normal(uint32_t frequency); +extern LIBHDHOMERUN_API uint32_t hdhomerun_channel_number_to_frequency(struct hdhomerun_channel_list_t *channel_list, uint16_t channel_number); +extern LIBHDHOMERUN_API uint16_t hdhomerun_channel_frequency_to_number(struct hdhomerun_channel_list_t *channel_list, uint32_t frequency); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_channelscan.c b/libhdhomerun/hdhomerun_channelscan.c index 8c1f8db..1e9ca4b 100644 --- a/libhdhomerun/hdhomerun_channelscan.c +++ b/libhdhomerun/hdhomerun_channelscan.c @@ -1,12 +1,12 @@ /* * hdhomerun_channelscan.c * - * Copyright © 2007-2010 Silicondust USA Inc. . + * Copyright © 2007-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" @@ -60,6 +48,7 @@ struct hdhomerun_channelscan_t *channelscan_create(struct hdhomerun_device_t *hd void channelscan_destroy(struct hdhomerun_channelscan_t *scan) { + hdhomerun_channel_list_destroy(scan->channel_list); free(scan); } @@ -67,7 +56,7 @@ static int channelscan_find_lock(struct hdhomerun_channelscan_t *scan, uint32_t { /* Set channel. */ char channel_str[64]; - sprintf(channel_str, "auto:%ld", (unsigned long)frequency); + hdhomerun_sprintf(channel_str, channel_str + sizeof(channel_str), "auto:%u", (unsigned int)frequency); int ret = hdhomerun_device_set_tuner_channel(scan->hd, channel_str); if (ret <= 0) { @@ -138,10 +127,10 @@ static void channelscan_extract_name(struct hdhomerun_channelscan_program_t *pro program->name[length] = 0; } -static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result, bool_t *pchanged, bool_t *pincomplete) +static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result, bool *pchanged, bool *pincomplete) { - *pchanged = FALSE; - *pincomplete = FALSE; + *pchanged = false; + *pincomplete = false; char *streaminfo; int ret = hdhomerun_device_get_tuner_streaminfo(scan->hd, &streaminfo); @@ -163,8 +152,15 @@ static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, str unsigned int transport_stream_id; if (sscanf(line, "tsid=0x%x", &transport_stream_id) == 1) { - result->transport_stream_id = transport_stream_id; - result->transport_stream_id_detected = TRUE; + result->transport_stream_id = (uint16_t)transport_stream_id; + result->transport_stream_id_detected = true; + continue; + } + + unsigned int original_network_id; + if (sscanf(line, "onid=0x%x", &original_network_id) == 1) { + result->original_network_id = (uint16_t)original_network_id; + result->original_network_id_detected = true; continue; } @@ -175,8 +171,7 @@ static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, str struct hdhomerun_channelscan_program_t program; memset(&program, 0, sizeof(program)); - strncpy(program.program_str, line, sizeof(program.program_str)); - program.program_str[sizeof(program.program_str) - 1] = 0; + hdhomerun_sprintf(program.program_str, program.program_str + sizeof(program.program_str), "%s", line); unsigned int program_number; unsigned int virtual_major, virtual_minor; @@ -187,9 +182,9 @@ static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, str virtual_minor = 0; } - program.program_number = program_number; - program.virtual_major = virtual_major; - program.virtual_minor = virtual_minor; + program.program_number = (uint16_t)program_number; + program.virtual_major = (uint16_t)virtual_major; + program.virtual_minor = (uint16_t)virtual_minor; channelscan_extract_name(&program, line); @@ -199,28 +194,28 @@ static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, str program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_ENCRYPTED; } else if (strstr(line, "(no data)")) { program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NODATA; - *pincomplete = TRUE; + *pincomplete = true; } else { program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NORMAL; if ((program.virtual_major == 0) || (program.name[0] == 0)) { - *pincomplete = TRUE; + *pincomplete = true; } } if (memcmp(&result->programs[program_count], &program, sizeof(program)) != 0) { memcpy(&result->programs[program_count], &program, sizeof(program)); - *pchanged = TRUE; + *pchanged = true; } program_count++; } if (program_count == 0) { - *pincomplete = TRUE; + *pincomplete = true; } if (result->program_count != program_count) { result->program_count = program_count; - *pchanged = TRUE; + *pchanged = true; } return 1; @@ -237,8 +232,10 @@ int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_c /* Combine channels with same frequency. */ result->frequency = hdhomerun_channel_entry_frequency(entry); - strncpy(result->channel_str, hdhomerun_channel_entry_name(entry), sizeof(result->channel_str) - 1); - result->channel_str[sizeof(result->channel_str) - 1] = 0; + + char *ptr = result->channel_str; + char *end = result->channel_str + sizeof(result->channel_str); + hdhomerun_sprintf(ptr, end, hdhomerun_channel_entry_name(entry)); while (1) { entry = hdhomerun_channel_list_prev(scan->channel_list, entry); @@ -252,8 +249,8 @@ int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_c break; } - char *ptr = strchr(result->channel_str, 0); - sprintf(ptr, ", %s", hdhomerun_channel_entry_name(entry)); + ptr = strchr(ptr, 0); + hdhomerun_sprintf(ptr, end, ", %s", hdhomerun_channel_entry_name(entry)); } return 1; @@ -285,7 +282,7 @@ int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_ch uint64_t complete_time = getcurrenttime() + 1000; while (1) { - bool_t changed, incomplete; + bool changed, incomplete; ret = channelscan_detect_programs(scan, result, &changed, &incomplete); if (ret <= 0) { return ret; @@ -346,5 +343,5 @@ uint8_t channelscan_get_progress(struct hdhomerun_channelscan_t *scan) } } - return scan->scanned_channels * 100 / (scan->scanned_channels + channels_remaining); + return (uint8_t) (scan->scanned_channels * 100 / (scan->scanned_channels + channels_remaining)); } diff --git a/libhdhomerun/hdhomerun_channelscan.h b/libhdhomerun/hdhomerun_channelscan.h index 8a1fac2..9306230 100644 --- a/libhdhomerun/hdhomerun_channelscan.h +++ b/libhdhomerun/hdhomerun_channelscan.h @@ -1,12 +1,12 @@ /* * hdhomerun_channelscan.h * - * Copyright © 2007-2008 Silicondust USA Inc. . + * Copyright © 2007-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus @@ -41,12 +29,12 @@ extern "C" { struct hdhomerun_channelscan_t; -extern LIBTYPE struct hdhomerun_channelscan_t *channelscan_create(struct hdhomerun_device_t *hd, const char *channelmap); -extern LIBTYPE void channelscan_destroy(struct hdhomerun_channelscan_t *scan); +extern LIBHDHOMERUN_API struct hdhomerun_channelscan_t *channelscan_create(struct hdhomerun_device_t *hd, const char *channelmap); +extern LIBHDHOMERUN_API void channelscan_destroy(struct hdhomerun_channelscan_t *scan); -extern LIBTYPE int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result); -extern LIBTYPE int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result); -extern LIBTYPE uint8_t channelscan_get_progress(struct hdhomerun_channelscan_t *scan); +extern LIBHDHOMERUN_API int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result); +extern LIBHDHOMERUN_API int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result); +extern LIBHDHOMERUN_API uint8_t channelscan_get_progress(struct hdhomerun_channelscan_t *scan); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_config.c b/libhdhomerun/hdhomerun_config.c index 6d8a792..8c5bace 100644 --- a/libhdhomerun/hdhomerun_config.c +++ b/libhdhomerun/hdhomerun_config.c @@ -1,12 +1,12 @@ /* * hdhomerun_config.c * - * Copyright © 2006-2008 Silicondust USA Inc. . + * Copyright © 2006-2017 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,34 +14,12 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" -/* - * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing. - * Attempting to restore on exit fails to restore if the program is terminated by the user. - * Solution - set the output format each printf. - */ -#if defined(__WINDOWS__) -#define printf console_printf -#define vprintf console_vprintf -#endif - static const char *appname; struct hdhomerun_device_t *hd; @@ -72,29 +50,29 @@ static void extract_appname(const char *argv0) appname = argv0; } -static bool_t contains(const char *arg, const char *cmpstr) +static bool contains(const char *arg, const char *cmpstr) { if (strcmp(arg, cmpstr) == 0) { - return TRUE; + return true; } if (*arg++ != '-') { - return FALSE; + return false; } if (*arg++ != '-') { - return FALSE; + return false; } if (strcmp(arg, cmpstr) == 0) { - return TRUE; + return true; } - return FALSE; + return false; } static uint32_t parse_ip_addr(const char *str) { - unsigned long a[4]; - if (sscanf(str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) { + unsigned int a[4]; + if (sscanf(str, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]) != 4) { return 0; } @@ -113,7 +91,7 @@ static int discover_print(char *target_ip_str) } struct hdhomerun_discover_device_t result_list[64]; - int count = hdhomerun_discover_find_devices_custom(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, 64); + int count = hdhomerun_discover_find_devices_custom_v2(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, 64); if (count < 0) { fprintf(stderr, "error sending discover request\n"); return -1; @@ -126,8 +104,8 @@ static int discover_print(char *target_ip_str) int index; for (index = 0; index < count; index++) { struct hdhomerun_discover_device_t *result = &result_list[index]; - printf("hdhomerun device %08lX found at %u.%u.%u.%u\n", - (unsigned long)result->device_id, + printf("hdhomerun device %08X found at %u.%u.%u.%u\n", + (unsigned int)result->device_id, (unsigned int)(result->ip_addr >> 24) & 0x0FF, (unsigned int)(result->ip_addr >> 16) & 0x0FF, (unsigned int)(result->ip_addr >> 8) & 0x0FF, (unsigned int)(result->ip_addr >> 0) & 0x0FF ); @@ -202,17 +180,17 @@ static int cmd_set(const char *item, const char *value) return cmd_set_internal(item, value); } -static volatile sig_atomic_t sigabort_flag = FALSE; -static volatile sig_atomic_t siginfo_flag = FALSE; +static volatile sig_atomic_t sigabort_flag = false; +static volatile sig_atomic_t siginfo_flag = false; static void sigabort_handler(int arg) { - sigabort_flag = TRUE; + sigabort_flag = true; } static void siginfo_handler(int arg) { - siginfo_flag = TRUE; + siginfo_flag = true; } static void register_signal_handlers(sig_t sigpipe_handler, sig_t sigint_handler, sig_t siginfo_handler) @@ -303,14 +281,17 @@ static int cmd_scan(const char *tuner_str, const char *filename) break; } - cmd_scan_printf(fp, "SCANNING: %lu (%s)\n", - (unsigned long)result.frequency, result.channel_str + cmd_scan_printf(fp, "SCANNING: %u (%s)\n", + (unsigned int)result.frequency, result.channel_str ); ret = hdhomerun_device_channelscan_detect(hd, &result); - if (ret <= 0) { + if (ret < 0) { break; } + if (ret == 0) { + continue; + } cmd_scan_printf(fp, "LOCK: %s (ss=%u snq=%u seq=%u)\n", result.status.lock_str, result.status.signal_strength, @@ -320,6 +301,9 @@ static int cmd_scan(const char *tuner_str, const char *filename) if (result.transport_stream_id_detected) { cmd_scan_printf(fp, "TSID: 0x%04X\n", result.transport_stream_id); } + if (result.original_network_id_detected) { + cmd_scan_printf(fp, "ONID: 0x%04X\n", result.original_network_id); + } int i; for (i = 0; i < result.program_count; i++) { @@ -395,7 +379,7 @@ static int cmd_save(const char *tuner_str, const char *filename) if (siginfo_flag) { fprintf(stderr, "\n"); cmd_save_print_stats(); - siginfo_flag = FALSE; + siginfo_flag = false; } size_t actual_size; @@ -419,7 +403,7 @@ static int cmd_save(const char *tuner_str, const char *filename) } /* Windows - indicate activity to suppress auto sleep mode. */ - #if defined(__WINDOWS__) + #if defined(_WIN32) SetThreadExecutionState(ES_SYSTEM_REQUIRED); #endif @@ -576,7 +560,7 @@ static int main_cmd(int argc, char *argv[]) if (argc < 2) { return help(); } - uint32_t lockkey = strtoul(argv[0], NULL, 0); + uint32_t lockkey = (uint32_t)strtoul(argv[0], NULL, 0); hdhomerun_device_tuner_lockkey_use_value(hd, lockkey); cmd = argv[1]; @@ -631,7 +615,9 @@ static int main_cmd(int argc, char *argv[]) static int main_internal(int argc, char *argv[]) { -#if defined(__WINDOWS__) +#if defined(_WIN32) + /* Configure console for UTF-8. */ + SetConsoleOutputCP(CP_UTF8); /* Initialize network socket support. */ WORD wVersionRequested = MAKEWORD(2, 0); WSADATA wsaData; @@ -668,7 +654,7 @@ static int main_internal(int argc, char *argv[]) /* Device ID check. */ uint32_t device_id_requested = hdhomerun_device_get_device_id_requested(hd); if (!hdhomerun_discover_validate_device_id(device_id_requested)) { - fprintf(stderr, "invalid device id: %08lX\n", (unsigned long)device_id_requested); + fprintf(stderr, "invalid device id: %08X\n", (unsigned int)device_id_requested); } /* Connect to device and check model. */ diff --git a/libhdhomerun/hdhomerun_control.c b/libhdhomerun/hdhomerun_control.c index 2873e53..cb323ef 100644 --- a/libhdhomerun/hdhomerun_control.c +++ b/libhdhomerun/hdhomerun_control.c @@ -1,12 +1,12 @@ /* * hdhomerun_control.c * - * Copyright © 2006-2010 Silicondust USA Inc. . + * Copyright © 2006-2016 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" @@ -35,14 +23,14 @@ #define HDHOMERUN_CONTROL_CONNECT_TIMEOUT 2500 #define HDHOMERUN_CONTROL_SEND_TIMEOUT 2500 #define HDHOMERUN_CONTROL_RECV_TIMEOUT 2500 -#define HDHOMERUN_CONTROL_UPGRADE_TIMEOUT 20000 +#define HDHOMERUN_CONTROL_UPGRADE_TIMEOUT 30000 struct hdhomerun_control_sock_t { uint32_t desired_device_id; uint32_t desired_device_ip; uint32_t actual_device_id; uint32_t actual_device_ip; - hdhomerun_sock_t sock; + struct hdhomerun_sock_t *sock; struct hdhomerun_debug_t *dbg; struct hdhomerun_pkt_t tx_pkt; struct hdhomerun_pkt_t rx_pkt; @@ -50,12 +38,12 @@ struct hdhomerun_control_sock_t { static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs) { - if (cs->sock == HDHOMERUN_SOCK_INVALID) { + if (!cs->sock) { return; } hdhomerun_sock_destroy(cs->sock); - cs->sock = HDHOMERUN_SOCK_INVALID; + cs->sock = NULL; } void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip) @@ -77,7 +65,6 @@ struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, ui } cs->dbg = dbg; - cs->sock = HDHOMERUN_SOCK_INVALID; hdhomerun_control_set_device(cs, device_id, device_ip); return cs; @@ -89,46 +76,46 @@ void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs) free(cs); } -static bool_t hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs) +static bool hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs) { - if (cs->sock != HDHOMERUN_SOCK_INVALID) { - return TRUE; + if (cs->sock) { + return true; } if ((cs->desired_device_id == 0) && (cs->desired_device_ip == 0)) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: no device specified\n"); - return FALSE; + return false; } if (hdhomerun_discover_is_ip_multicast(cs->desired_device_ip)) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: cannot use multicast ip address for device operations\n"); - return FALSE; + return false; } /* Find device. */ struct hdhomerun_discover_device_t result; - if (hdhomerun_discover_find_devices_custom(cs->desired_device_ip, HDHOMERUN_DEVICE_TYPE_WILDCARD, cs->desired_device_id, &result, 1) <= 0) { + if (hdhomerun_discover_find_devices_custom_v2(cs->desired_device_ip, HDHOMERUN_DEVICE_TYPE_WILDCARD, cs->desired_device_id, &result, 1) <= 0) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: device not found\n"); - return FALSE; + return false; } cs->actual_device_ip = result.ip_addr; cs->actual_device_id = result.device_id; /* Create socket. */ cs->sock = hdhomerun_sock_create_tcp(); - if (cs->sock == HDHOMERUN_SOCK_INVALID) { + if (!cs->sock) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to create socket (%d)\n", hdhomerun_sock_getlasterror()); - return FALSE; + return false; } /* Initiate connection. */ if (!hdhomerun_sock_connect(cs->sock, cs->actual_device_ip, HDHOMERUN_CONTROL_TCP_PORT, HDHOMERUN_CONTROL_CONNECT_TIMEOUT)) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to connect (%d)\n", hdhomerun_sock_getlasterror()); hdhomerun_control_close_sock(cs); - return FALSE; + return false; } /* Success. */ - return TRUE; + return true; } uint32_t hdhomerun_control_get_device_id(struct hdhomerun_control_sock_t *cs) @@ -177,18 +164,18 @@ uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs) return addr; } -static bool_t hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt) +static bool hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt) { if (!hdhomerun_sock_send(cs->sock, tx_pkt->start, tx_pkt->end - tx_pkt->start, HDHOMERUN_CONTROL_SEND_TIMEOUT)) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_sock: send failed (%d)\n", hdhomerun_sock_getlasterror()); hdhomerun_control_close_sock(cs); - return FALSE; + return false; } - return TRUE; + return true; } -static bool_t hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *rx_pkt, uint16_t *ptype, uint64_t recv_timeout) +static bool hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *rx_pkt, uint16_t *ptype, uint64_t recv_timeout) { uint64_t stop_time = getcurrenttime() + recv_timeout; hdhomerun_pkt_reset(rx_pkt); @@ -198,14 +185,14 @@ static bool_t hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, s if (current_time >= stop_time) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: timeout\n"); hdhomerun_control_close_sock(cs); - return FALSE; + return false; } size_t length = rx_pkt->limit - rx_pkt->end; if (!hdhomerun_sock_recv(cs->sock, rx_pkt->end, &length, stop_time - current_time)) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: recv failed (%d)\n", hdhomerun_sock_getlasterror()); hdhomerun_control_close_sock(cs); - return FALSE; + return false; } rx_pkt->end += length; @@ -214,10 +201,10 @@ static bool_t hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, s if (ret < 0) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: frame error\n"); hdhomerun_control_close_sock(cs); - return FALSE; + return false; } if (ret > 0) { - return TRUE; + return true; } } } @@ -228,7 +215,7 @@ static int hdhomerun_control_send_recv_internal(struct hdhomerun_control_sock_t int i; for (i = 0; i < 2; i++) { - if (cs->sock == HDHOMERUN_SOCK_INVALID) { + if (!cs->sock) { if (!hdhomerun_control_connect_sock(cs)) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_recv: connect failed\n"); return -1; @@ -272,7 +259,7 @@ static int hdhomerun_control_get_set(struct hdhomerun_control_sock_t *cs, const /* Request. */ hdhomerun_pkt_reset(tx_pkt); - int name_len = (int)strlen(name) + 1; + size_t name_len = strlen(name) + 1; if (tx_pkt->end + 3 + name_len > tx_pkt->limit) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: request too long\n"); return -1; @@ -282,7 +269,7 @@ static int hdhomerun_control_get_set(struct hdhomerun_control_sock_t *cs, const hdhomerun_pkt_write_mem(tx_pkt, (const void *)name, name_len); if (value) { - int value_len = (int)strlen(value) + 1; + size_t value_len = strlen(value) + 1; if (tx_pkt->end + 3 + value_len > tx_pkt->limit) { hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: request too long\n"); return -1; @@ -340,6 +327,9 @@ static int hdhomerun_control_get_set(struct hdhomerun_control_sock_t *cs, const } return 0; + + default: + break; } rx_pkt->pos = next; @@ -368,12 +358,20 @@ int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade { struct hdhomerun_pkt_t *tx_pkt = &cs->tx_pkt; struct hdhomerun_pkt_t *rx_pkt = &cs->rx_pkt; + bool upload_delay = false; uint32_t sequence = 0; + /* Special case detection. */ + char *version_str; + int ret = hdhomerun_control_get(cs, "/sys/version", &version_str, NULL); + if (ret > 0) { + upload_delay = strcmp(version_str, "20120704beta1") == 0; + } + /* Upload. */ while (1) { - uint8_t data[256]; - size_t length = fread(data, 1, 256, upgrade_file); + uint8_t data[1024]; + size_t length = fread(data, 1, 1024, upgrade_file); if (length == 0) { break; } @@ -388,6 +386,10 @@ int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade } sequence += (uint32_t)length; + + if (upload_delay) { + msleep_approx(25); + } } if (sequence == 0) { diff --git a/libhdhomerun/hdhomerun_control.h b/libhdhomerun/hdhomerun_control.h index 9960066..a598ce2 100644 --- a/libhdhomerun/hdhomerun_control.h +++ b/libhdhomerun/hdhomerun_control.h @@ -1,12 +1,12 @@ /* * hdhomerun_control.h * - * Copyright © 2006 Silicondust USA Inc. . + * Copyright © 2006-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus extern "C" { @@ -49,20 +37,20 @@ struct hdhomerun_control_sock_t; * * When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy. */ -extern LIBTYPE struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip, struct hdhomerun_debug_t *dbg); -extern LIBTYPE void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs); +extern LIBHDHOMERUN_API struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip, struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs); /* * Get the actual device id or ip of the device. * * Returns 0 if the device id cannot be determined. */ -extern LIBTYPE uint32_t hdhomerun_control_get_device_id(struct hdhomerun_control_sock_t *cs); -extern LIBTYPE uint32_t hdhomerun_control_get_device_ip(struct hdhomerun_control_sock_t *cs); -extern LIBTYPE uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock_t *cs); -extern LIBTYPE uint32_t hdhomerun_control_get_device_ip_requested(struct hdhomerun_control_sock_t *cs); +extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_id(struct hdhomerun_control_sock_t *cs); +extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_ip(struct hdhomerun_control_sock_t *cs); +extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock_t *cs); +extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_device_ip_requested(struct hdhomerun_control_sock_t *cs); -extern LIBTYPE void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip); +extern LIBHDHOMERUN_API void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip); /* * Get the local machine IP address used when communicating with the device. @@ -71,12 +59,12 @@ extern LIBTYPE void hdhomerun_control_set_device(struct hdhomerun_control_sock_t * * Returns 32-bit IP address with native endianness, or 0 on error. */ -extern LIBTYPE uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs); +extern LIBHDHOMERUN_API uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs); /* * Low-level communication. */ -extern LIBTYPE int hdhomerun_control_send_recv(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt, struct hdhomerun_pkt_t *rx_pkt, uint16_t type); +extern LIBHDHOMERUN_API int hdhomerun_control_send_recv(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt, struct hdhomerun_pkt_t *rx_pkt, uint16_t type); /* * Get/set a control variable on the device. @@ -95,9 +83,9 @@ extern LIBTYPE int hdhomerun_control_send_recv(struct hdhomerun_control_sock_t * * Returns 0 if the operation was rejected (pvalue NULL, perror set). * Returns -1 if a communication error occurs. */ -extern LIBTYPE int hdhomerun_control_get(struct hdhomerun_control_sock_t *cs, const char *name, char **pvalue, char **perror); -extern LIBTYPE int hdhomerun_control_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror); -extern LIBTYPE int hdhomerun_control_set_with_lockkey(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, uint32_t lockkey, char **pvalue, char **perror); +extern LIBHDHOMERUN_API int hdhomerun_control_get(struct hdhomerun_control_sock_t *cs, const char *name, char **pvalue, char **perror); +extern LIBHDHOMERUN_API int hdhomerun_control_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror); +extern LIBHDHOMERUN_API int hdhomerun_control_set_with_lockkey(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, uint32_t lockkey, char **pvalue, char **perror); /* * Upload new firmware to the device. @@ -108,7 +96,7 @@ extern LIBTYPE int hdhomerun_control_set_with_lockkey(struct hdhomerun_control_s * Returns 0 if the upload was rejected. * Returns -1 if an error occurs. */ -extern LIBTYPE int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade_file); +extern LIBHDHOMERUN_API int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade_file); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_debug.c b/libhdhomerun/hdhomerun_debug.c index 9686f61..4a44b9c 100644 --- a/libhdhomerun/hdhomerun_debug.c +++ b/libhdhomerun/hdhomerun_debug.c @@ -1,12 +1,12 @@ /* * hdhomerun_debug.c * - * Copyright © 2006-2010 Silicondust USA Inc. . + * Copyright © 2007-2016 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* @@ -54,21 +42,21 @@ struct hdhomerun_debug_message_t { struct hdhomerun_debug_message_t *next; - struct hdhomerun_debug_message_t *prev; char buffer[2048]; }; struct hdhomerun_debug_t { - pthread_t thread; - volatile bool_t enabled; - volatile bool_t terminate; + thread_task_t thread; + volatile bool enabled; + volatile bool terminate; char *prefix; - pthread_mutex_t print_lock; - pthread_mutex_t queue_lock; - pthread_mutex_t send_lock; + thread_mutex_t print_lock; + thread_mutex_t queue_lock; + thread_mutex_t send_lock; + thread_cond_t queue_cond; struct hdhomerun_debug_message_t *queue_head; struct hdhomerun_debug_message_t *queue_tail; uint32_t queue_depth; @@ -77,10 +65,10 @@ struct hdhomerun_debug_t char *file_name; FILE *file_fp; - hdhomerun_sock_t sock; + struct hdhomerun_sock_t *sock; }; -static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg); +static void hdhomerun_debug_thread_execute(void *arg); struct hdhomerun_debug_t *hdhomerun_debug_create(void) { @@ -89,13 +77,12 @@ struct hdhomerun_debug_t *hdhomerun_debug_create(void) return NULL; } - dbg->sock = HDHOMERUN_SOCK_INVALID; + thread_mutex_init(&dbg->print_lock); + thread_mutex_init(&dbg->queue_lock); + thread_mutex_init(&dbg->send_lock); + thread_cond_init(&dbg->queue_cond); - pthread_mutex_init(&dbg->print_lock, NULL); - pthread_mutex_init(&dbg->queue_lock, NULL); - pthread_mutex_init(&dbg->send_lock, NULL); - - if (pthread_create(&dbg->thread, NULL, &hdhomerun_debug_thread_execute, dbg) != 0) { + if (!thread_task_create(&dbg->thread, &hdhomerun_debug_thread_execute, dbg)) { free(dbg); return NULL; } @@ -109,8 +96,9 @@ void hdhomerun_debug_destroy(struct hdhomerun_debug_t *dbg) return; } - dbg->terminate = TRUE; - pthread_join(dbg->thread, NULL); + dbg->terminate = true; + thread_cond_signal(&dbg->queue_cond); + thread_task_join(dbg->thread); if (dbg->prefix) { free(dbg->prefix); @@ -121,10 +109,14 @@ void hdhomerun_debug_destroy(struct hdhomerun_debug_t *dbg) if (dbg->file_fp) { fclose(dbg->file_fp); } - if (dbg->sock != HDHOMERUN_SOCK_INVALID) { + if (dbg->sock) { hdhomerun_sock_destroy(dbg->sock); } + thread_cond_dispose(&dbg->queue_cond); + thread_mutex_dispose(&dbg->print_lock); + thread_mutex_dispose(&dbg->queue_lock); + thread_mutex_dispose(&dbg->send_lock); free(dbg); } @@ -136,9 +128,9 @@ static void hdhomerun_debug_close_internal(struct hdhomerun_debug_t *dbg) dbg->file_fp = NULL; } - if (dbg->sock != HDHOMERUN_SOCK_INVALID) { + if (dbg->sock) { hdhomerun_sock_destroy(dbg->sock); - dbg->sock = HDHOMERUN_SOCK_INVALID; + dbg->sock = NULL; } } @@ -152,10 +144,10 @@ void hdhomerun_debug_close(struct hdhomerun_debug_t *dbg, uint64_t timeout) hdhomerun_debug_flush(dbg, timeout); } - pthread_mutex_lock(&dbg->send_lock); + thread_mutex_lock(&dbg->send_lock); hdhomerun_debug_close_internal(dbg); dbg->connect_delay = 0; - pthread_mutex_unlock(&dbg->send_lock); + thread_mutex_unlock(&dbg->send_lock); } void hdhomerun_debug_set_filename(struct hdhomerun_debug_t *dbg, const char *filename) @@ -164,15 +156,15 @@ void hdhomerun_debug_set_filename(struct hdhomerun_debug_t *dbg, const char *fil return; } - pthread_mutex_lock(&dbg->send_lock); + thread_mutex_lock(&dbg->send_lock); if (!filename && !dbg->file_name) { - pthread_mutex_unlock(&dbg->send_lock); + thread_mutex_unlock(&dbg->send_lock); return; } if (filename && dbg->file_name) { if (strcmp(filename, dbg->file_name) == 0) { - pthread_mutex_unlock(&dbg->send_lock); + thread_mutex_unlock(&dbg->send_lock); return; } } @@ -188,7 +180,7 @@ void hdhomerun_debug_set_filename(struct hdhomerun_debug_t *dbg, const char *fil dbg->file_name = strdup(filename); } - pthread_mutex_unlock(&dbg->send_lock); + thread_mutex_unlock(&dbg->send_lock); } void hdhomerun_debug_set_prefix(struct hdhomerun_debug_t *dbg, const char *prefix) @@ -197,7 +189,7 @@ void hdhomerun_debug_set_prefix(struct hdhomerun_debug_t *dbg, const char *prefi return; } - pthread_mutex_lock(&dbg->print_lock); + thread_mutex_lock(&dbg->print_lock); if (dbg->prefix) { free(dbg->prefix); @@ -208,7 +200,7 @@ void hdhomerun_debug_set_prefix(struct hdhomerun_debug_t *dbg, const char *prefi dbg->prefix = strdup(prefix); } - pthread_mutex_unlock(&dbg->print_lock); + thread_mutex_unlock(&dbg->print_lock); } void hdhomerun_debug_enable(struct hdhomerun_debug_t *dbg) @@ -216,8 +208,12 @@ void hdhomerun_debug_enable(struct hdhomerun_debug_t *dbg) if (!dbg) { return; } + if (dbg->enabled) { + return; + } - dbg->enabled = TRUE; + dbg->enabled = true; + thread_cond_signal(&dbg->queue_cond); } void hdhomerun_debug_disable(struct hdhomerun_debug_t *dbg) @@ -226,13 +222,13 @@ void hdhomerun_debug_disable(struct hdhomerun_debug_t *dbg) return; } - dbg->enabled = FALSE; + dbg->enabled = false; } -bool_t hdhomerun_debug_enabled(struct hdhomerun_debug_t *dbg) +bool hdhomerun_debug_enabled(struct hdhomerun_debug_t *dbg) { if (!dbg) { - return FALSE; + return false; } return dbg->enabled; @@ -247,15 +243,15 @@ void hdhomerun_debug_flush(struct hdhomerun_debug_t *dbg, uint64_t timeout) timeout = getcurrenttime() + timeout; while (getcurrenttime() < timeout) { - pthread_mutex_lock(&dbg->queue_lock); - struct hdhomerun_debug_message_t *message = dbg->queue_tail; - pthread_mutex_unlock(&dbg->queue_lock); + thread_mutex_lock(&dbg->queue_lock); + struct hdhomerun_debug_message_t *message = dbg->queue_head; + thread_mutex_unlock(&dbg->queue_lock); if (!message) { return; } - msleep_approx(10); + msleep_approx(16); } } @@ -272,15 +268,14 @@ void hdhomerun_debug_vprintf(struct hdhomerun_debug_t *dbg, const char *fmt, va_ if (!dbg) { return; } - if (!dbg->enabled) { - return; - } struct hdhomerun_debug_message_t *message = (struct hdhomerun_debug_message_t *)malloc(sizeof(struct hdhomerun_debug_message_t)); if (!message) { return; } + message->next = NULL; + char *ptr = message->buffer; char *end = message->buffer + sizeof(message->buffer) - 2; *end = 0; @@ -297,166 +292,151 @@ void hdhomerun_debug_vprintf(struct hdhomerun_debug_t *dbg, const char *fmt, va_ /* * Debug prefix. */ - pthread_mutex_lock(&dbg->print_lock); + thread_mutex_lock(&dbg->print_lock); if (dbg->prefix) { - int len = snprintf(ptr, end - ptr, "%s ", dbg->prefix); - len = (len <= 0) ? 0 : len; - ptr += len; - if (ptr > end) { - ptr = end; - } + hdhomerun_sprintf(ptr, end, "%s ", dbg->prefix); + ptr = strchr(ptr, 0); } - pthread_mutex_unlock(&dbg->print_lock); + thread_mutex_unlock(&dbg->print_lock); /* * Message text. */ - int len = vsnprintf(ptr, end - ptr, fmt, args); - len = (len < 0) ? 0 : len; /* len does not include null */ - ptr += len; - if (ptr > end) { - ptr = end; - } + hdhomerun_vsprintf(ptr, end, fmt, args); + ptr = strchr(ptr, 0); /* * Force newline. */ - if ((ptr[-1] != '\n') && (ptr + 1 <= end)) { - *ptr++ = '\n'; + if (ptr[-1] != '\n') { + hdhomerun_sprintf(ptr, end, "\n"); } - /* - * Force NULL. - */ - if (ptr + 1 > end) { - ptr = end - 1; - } - *ptr++ = 0; - /* * Enqueue. */ - pthread_mutex_lock(&dbg->queue_lock); + thread_mutex_lock(&dbg->queue_lock); - message->prev = NULL; - message->next = dbg->queue_head; - dbg->queue_head = message; - if (message->next) { - message->next->prev = message; + if (dbg->queue_tail) { + dbg->queue_tail->next = message; } else { - dbg->queue_tail = message; + dbg->queue_head = message; } + dbg->queue_tail = message; dbg->queue_depth++; - pthread_mutex_unlock(&dbg->queue_lock); + bool signal_thread = dbg->enabled || (dbg->queue_depth > 1024 + 100); + + thread_mutex_unlock(&dbg->queue_lock); + + if (signal_thread) { + thread_cond_signal(&dbg->queue_cond); + } } /* Send lock held by caller */ -static bool_t hdhomerun_debug_output_message_file(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) +static bool hdhomerun_debug_output_message_file(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) { if (!dbg->file_fp) { uint64_t current_time = getcurrenttime(); if (current_time < dbg->connect_delay) { - return FALSE; + return false; } dbg->connect_delay = current_time + 30*1000; dbg->file_fp = fopen(dbg->file_name, "a"); if (!dbg->file_fp) { - return FALSE; + return false; } } fprintf(dbg->file_fp, "%s", message->buffer); fflush(dbg->file_fp); - return TRUE; + return true; } /* Send lock held by caller */ -static bool_t hdhomerun_debug_output_message_sock(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) +static bool hdhomerun_debug_output_message_sock(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) { - if (dbg->sock == HDHOMERUN_SOCK_INVALID) { + if (!dbg->sock) { uint64_t current_time = getcurrenttime(); if (current_time < dbg->connect_delay) { - return FALSE; + return false; } dbg->connect_delay = current_time + HDHOMERUN_DEBUG_CONNECT_RETRY_TIME; dbg->sock = hdhomerun_sock_create_tcp(); - if (dbg->sock == HDHOMERUN_SOCK_INVALID) { - return FALSE; + if (!dbg->sock) { + return false; } uint32_t remote_addr = hdhomerun_sock_getaddrinfo_addr(dbg->sock, HDHOMERUN_DEBUG_HOST); if (remote_addr == 0) { hdhomerun_debug_close_internal(dbg); - return FALSE; + return false; } if (!hdhomerun_sock_connect(dbg->sock, remote_addr, HDHOMERUN_DEBUG_PORT, HDHOMERUN_DEBUG_CONNECT_TIMEOUT)) { hdhomerun_debug_close_internal(dbg); - return FALSE; + return false; } } size_t length = strlen(message->buffer); if (!hdhomerun_sock_send(dbg->sock, message->buffer, length, HDHOMERUN_DEBUG_SEND_TIMEOUT)) { hdhomerun_debug_close_internal(dbg); - return FALSE; + return false; } - return TRUE; + return true; } -static bool_t hdhomerun_debug_output_message(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) +static bool hdhomerun_debug_output_message(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message) { - pthread_mutex_lock(&dbg->send_lock); + thread_mutex_lock(&dbg->send_lock); - bool_t ret; + bool ret; if (dbg->file_name) { ret = hdhomerun_debug_output_message_file(dbg, message); } else { ret = hdhomerun_debug_output_message_sock(dbg, message); } - pthread_mutex_unlock(&dbg->send_lock); + thread_mutex_unlock(&dbg->send_lock); return ret; } static void hdhomerun_debug_pop_and_free_message(struct hdhomerun_debug_t *dbg) { - pthread_mutex_lock(&dbg->queue_lock); + thread_mutex_lock(&dbg->queue_lock); - struct hdhomerun_debug_message_t *message = dbg->queue_tail; - dbg->queue_tail = message->prev; - if (message->prev) { - message->prev->next = NULL; - } else { - dbg->queue_head = NULL; + struct hdhomerun_debug_message_t *message = dbg->queue_head; + dbg->queue_head = message->next; + if (!dbg->queue_head) { + dbg->queue_tail = NULL; } dbg->queue_depth--; - pthread_mutex_unlock(&dbg->queue_lock); + thread_mutex_unlock(&dbg->queue_lock); free(message); } -static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg) +static void hdhomerun_debug_thread_execute(void *arg) { struct hdhomerun_debug_t *dbg = (struct hdhomerun_debug_t *)arg; while (!dbg->terminate) { - - pthread_mutex_lock(&dbg->queue_lock); - struct hdhomerun_debug_message_t *message = dbg->queue_tail; + thread_mutex_lock(&dbg->queue_lock); + struct hdhomerun_debug_message_t *message = dbg->queue_head; uint32_t queue_depth = dbg->queue_depth; - pthread_mutex_unlock(&dbg->queue_lock); + thread_mutex_unlock(&dbg->queue_lock); if (!message) { - msleep_approx(250); + thread_cond_wait(&dbg->queue_cond); continue; } @@ -465,13 +445,16 @@ static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg) continue; } + if (!dbg->enabled) { + thread_cond_wait(&dbg->queue_cond); + continue; + } + if (!hdhomerun_debug_output_message(dbg, message)) { - msleep_approx(250); + msleep_approx(1000); continue; } hdhomerun_debug_pop_and_free_message(dbg); } - - return 0; } diff --git a/libhdhomerun/hdhomerun_debug.h b/libhdhomerun/hdhomerun_debug.h index c7831ea..1e9a45d 100644 --- a/libhdhomerun/hdhomerun_debug.h +++ b/libhdhomerun/hdhomerun_debug.h @@ -1,12 +1,12 @@ /* * hdhomerun_debug.h * - * Copyright © 2006 Silicondust USA Inc. . + * Copyright © 2007-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* @@ -44,20 +32,20 @@ extern "C" { struct hdhomerun_debug_t; -extern LIBTYPE struct hdhomerun_debug_t *hdhomerun_debug_create(void); -extern LIBTYPE void hdhomerun_debug_destroy(struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API struct hdhomerun_debug_t *hdhomerun_debug_create(void); +extern LIBHDHOMERUN_API void hdhomerun_debug_destroy(struct hdhomerun_debug_t *dbg); -extern LIBTYPE void hdhomerun_debug_set_prefix(struct hdhomerun_debug_t *dbg, const char *prefix); -extern LIBTYPE void hdhomerun_debug_set_filename(struct hdhomerun_debug_t *dbg, const char *filename); -extern LIBTYPE void hdhomerun_debug_enable(struct hdhomerun_debug_t *dbg); -extern LIBTYPE void hdhomerun_debug_disable(struct hdhomerun_debug_t *dbg); -extern LIBTYPE bool_t hdhomerun_debug_enabled(struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API void hdhomerun_debug_set_prefix(struct hdhomerun_debug_t *dbg, const char *prefix); +extern LIBHDHOMERUN_API void hdhomerun_debug_set_filename(struct hdhomerun_debug_t *dbg, const char *filename); +extern LIBHDHOMERUN_API void hdhomerun_debug_enable(struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API void hdhomerun_debug_disable(struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API bool hdhomerun_debug_enabled(struct hdhomerun_debug_t *dbg); -extern LIBTYPE void hdhomerun_debug_flush(struct hdhomerun_debug_t *dbg, uint64_t timeout); -extern LIBTYPE void hdhomerun_debug_close(struct hdhomerun_debug_t *dbg, uint64_t timeout); +extern LIBHDHOMERUN_API void hdhomerun_debug_flush(struct hdhomerun_debug_t *dbg, uint64_t timeout); +extern LIBHDHOMERUN_API void hdhomerun_debug_close(struct hdhomerun_debug_t *dbg, uint64_t timeout); -extern LIBTYPE void hdhomerun_debug_printf(struct hdhomerun_debug_t *dbg, const char *fmt, ...); -extern LIBTYPE void hdhomerun_debug_vprintf(struct hdhomerun_debug_t *dbg, const char *fmt, va_list args); +extern LIBHDHOMERUN_API void hdhomerun_debug_printf(struct hdhomerun_debug_t *dbg, const char *fmt, ...); +extern LIBHDHOMERUN_API void hdhomerun_debug_vprintf(struct hdhomerun_debug_t *dbg, const char *fmt, va_list args); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_device.c b/libhdhomerun/hdhomerun_device.c index d884d32..ff2650b 100644 --- a/libhdhomerun/hdhomerun_device.c +++ b/libhdhomerun/hdhomerun_device.c @@ -1,12 +1,12 @@ /* * hdhomerun_device.c * - * Copyright © 2006-2010 Silicondust USA Inc. . + * Copyright © 2006-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" @@ -46,8 +34,18 @@ struct hdhomerun_device_t { char model[32]; }; -static int hdhomerun_device_set_device_normal(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip) +int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip) { + if ((device_id == 0) && (device_ip == 0)) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: device not specified\n"); + return -1; + } + + if (hdhomerun_discover_is_ip_multicast(device_ip)) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: invalid address %08X\n", (unsigned int)device_ip); + return -1; + } + if (!hd->cs) { hd->cs = hdhomerun_control_create(0, 0, hd->dbg); if (!hd->cs) { @@ -68,46 +66,42 @@ static int hdhomerun_device_set_device_normal(struct hdhomerun_device_t *hd, uin hd->tuner = 0; hd->lockkey = 0; - sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner); - hd->model[0] = 0; /* clear cached model string */ + hdhomerun_sprintf(hd->name, hd->name + sizeof(hd->name), "%08X-%u", (unsigned int)hd->device_id, hd->tuner); + hdhomerun_sprintf(hd->model, hd->model + sizeof(hd->model), ""); /* clear cached model string */ return 1; } -static int hdhomerun_device_set_device_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip) +int hdhomerun_device_set_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip, uint16_t multicast_port) { + if (!hdhomerun_discover_is_ip_multicast(multicast_ip)) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device_multicast: invalid address %08X\n", (unsigned int)multicast_ip); + return -1; + } + + if (multicast_port == 0) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device_multicast: invalid port %u\n", (unsigned int)multicast_port); + return -1; + } + if (hd->cs) { hdhomerun_control_destroy(hd->cs); hd->cs = NULL; } hd->multicast_ip = multicast_ip; - hd->multicast_port = 0; + hd->multicast_port = multicast_port; hd->device_id = 0; hd->tuner = 0; hd->lockkey = 0; - unsigned long ip = multicast_ip; - sprintf(hd->name, "%lu.%lu.%lu.%lu", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF); - sprintf(hd->model, "multicast"); + unsigned int ip = multicast_ip; + hdhomerun_sprintf(hd->name, hd->name + sizeof(hd->name), "%u.%u.%u.%u:%u", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF, (unsigned int)multicast_port); + hdhomerun_sprintf(hd->model, hd->model + sizeof(hd->model), "multicast"); return 1; } -int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip) -{ - if ((device_id == 0) && (device_ip == 0)) { - hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: device not specified\n"); - return -1; - } - - if (hdhomerun_discover_is_ip_multicast(device_ip)) { - return hdhomerun_device_set_device_multicast(hd, device_ip); - } - - return hdhomerun_device_set_device_normal(hd, device_id, device_ip); -} - int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner) { if (hd->multicast_ip != 0) { @@ -120,20 +114,44 @@ int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner } hd->tuner = tuner; - sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner); + hdhomerun_sprintf(hd->name, hd->name + sizeof(hd->name), "%08X-%u", (unsigned int)hd->device_id, hd->tuner); return 1; } -struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg) +int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str) +{ + unsigned int tuner; + if (sscanf(tuner_str, "%u", &tuner) == 1) { + hdhomerun_device_set_tuner(hd, tuner); + return 1; + } + if (sscanf(tuner_str, "/tuner%u", &tuner) == 1) { + hdhomerun_device_set_tuner(hd, tuner); + return 1; + } + + return -1; +} + +static struct hdhomerun_device_t *hdhomerun_device_create_internal(struct hdhomerun_debug_t *dbg) { struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)calloc(1, sizeof(struct hdhomerun_device_t)); if (!hd) { - hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_create: failed to allocate device object\n"); + hdhomerun_debug_printf(dbg, "hdhomerun_device_create: failed to allocate device object\n"); return NULL; } hd->dbg = dbg; + return hd; +} + +struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg) +{ + struct hdhomerun_device_t *hd = hdhomerun_device_create_internal(dbg); + if (!hd) { + return NULL; + } if ((device_id == 0) && (device_ip == 0) && (tuner == 0)) { return hd; @@ -151,6 +169,21 @@ struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t return hd; } +struct hdhomerun_device_t *hdhomerun_device_create_multicast(uint32_t multicast_ip, uint16_t multicast_port, struct hdhomerun_debug_t *dbg) +{ + struct hdhomerun_device_t *hd = hdhomerun_device_create_internal(dbg); + if (!hd) { + return NULL; + } + + if (hdhomerun_device_set_multicast(hd, multicast_ip, multicast_port) <= 0) { + free(hd); + return NULL; + } + + return hd; +} + void hdhomerun_device_destroy(struct hdhomerun_device_t *hd) { if (hd->scan) { @@ -168,78 +201,60 @@ void hdhomerun_device_destroy(struct hdhomerun_device_t *hd) free(hd); } -static bool_t is_hex_char(char c) -{ - if ((c >= '0') && (c <= '9')) { - return TRUE; - } - if ((c >= 'A') && (c <= 'F')) { - return TRUE; - } - if ((c >= 'a') && (c <= 'f')) { - return TRUE; - } - return FALSE; -} - -static struct hdhomerun_device_t *hdhomerun_device_create_from_str_device_id(const char *device_str, struct hdhomerun_debug_t *dbg) +struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg) { - int i; - const char *ptr = device_str; - for (i = 0; i < 8; i++) { - if (!is_hex_char(*ptr++)) { - return NULL; - } - } - - if (*ptr == 0) { - unsigned long device_id; - if (sscanf(device_str, "%lx", &device_id) != 1) { - return NULL; + /* + * IP address based device_str. + */ + unsigned int a[4]; + if (sscanf(device_str, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]) == 4) { + uint32_t ip_addr = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0)); + + /* + * Multicast IP address. + */ + unsigned int port; + if (sscanf(device_str, "%u.%u.%u.%u:%u", &a[0], &a[1], &a[2], &a[3], &port) == 5) { + return hdhomerun_device_create_multicast(ip_addr, (uint16_t)port, dbg); } - return hdhomerun_device_create((uint32_t)device_id, 0, 0, dbg); - } - if (*ptr == '-') { - unsigned long device_id; + /* + * IP address + tuner number. + */ unsigned int tuner; - if (sscanf(device_str, "%lx-%u", &device_id, &tuner) != 2) { - return NULL; + if (sscanf(device_str, "%u.%u.%u.%u-%u", &a[0], &a[1], &a[2], &a[3], &tuner) == 5) { + return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, tuner, dbg); } - return hdhomerun_device_create((uint32_t)device_id, 0, tuner, dbg); - } - return NULL; -} - -static struct hdhomerun_device_t *hdhomerun_device_create_from_str_ip(const char *device_str, struct hdhomerun_debug_t *dbg) -{ - unsigned long a[4]; - unsigned int port = 0; - if (sscanf(device_str, "%lu.%lu.%lu.%lu:%u", &a[0], &a[1], &a[2], &a[3], &port) != 5) { - if (sscanf(device_str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) { - return NULL; + /* + * IP address only. + */ + return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, 0, dbg); + } + + /* + * Device ID based device_str. + */ + char *end; + uint32_t device_id = (uint32_t)strtoul(device_str, &end, 16); + if ((end == device_str + 8) && hdhomerun_discover_validate_device_id(device_id)) { + /* + * IP address + tuner number. + */ + if (*end == '-') { + unsigned int tuner = (unsigned int)strtoul(end + 1, NULL, 10); + return hdhomerun_device_create(device_id, 0, tuner, dbg); } - } - - unsigned long device_ip = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0); - struct hdhomerun_device_t *hd = hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, 0, dbg); - if (!hd) { - return NULL; - } - if (hd->multicast_ip != 0) { - hd->multicast_port = port; + /* + * Device ID only. + */ + return hdhomerun_device_create(device_id, 0, 0, dbg); } - return hd; -} - -static struct hdhomerun_device_t *hdhomerun_device_create_from_str_dns(const char *device_str, struct hdhomerun_debug_t *dbg) -{ -#if defined(__CYGWIN__) - return NULL; -#else + /* + * DNS based device_str. + */ struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; @@ -252,50 +267,14 @@ static struct hdhomerun_device_t *hdhomerun_device_create_from_str_dns(const cha } struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr; - uint32_t device_ip = ntohl(sock_addr->sin_addr.s_addr); + uint32_t ip_addr = (uint32_t)ntohl(sock_addr->sin_addr.s_addr); freeaddrinfo(sock_info); - if (device_ip == 0) { + if (ip_addr == 0) { return NULL; } - return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, 0, dbg); -#endif -} - -struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg) -{ - struct hdhomerun_device_t *device = hdhomerun_device_create_from_str_device_id(device_str, dbg); - if (device) { - return device; - } - - device = hdhomerun_device_create_from_str_ip(device_str, dbg); - if (device) { - return device; - } - - device = hdhomerun_device_create_from_str_dns(device_str, dbg); - if (device) { - return device; - } - - return NULL; -} - -int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str) -{ - unsigned int tuner; - if (sscanf(tuner_str, "%u", &tuner) == 1) { - hdhomerun_device_set_tuner(hd, tuner); - return 1; - } - if (sscanf(tuner_str, "/tuner%u", &tuner) == 1) { - hdhomerun_device_set_tuner(hd, tuner); - return 1; - } - - return -1; + return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, 0, dbg); } const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd) @@ -360,7 +339,9 @@ struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_ return hd->vs; } - hd->vs = hdhomerun_video_create(hd->multicast_port, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg); + bool allow_port_reuse = (hd->multicast_port != 0); + + hd->vs = hdhomerun_video_create(hd->multicast_port, allow_port_reuse, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg); if (!hd->vs) { hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_video_sock: failed to create video object\n"); return NULL; @@ -385,28 +366,28 @@ static uint32_t hdhomerun_device_get_status_parse(const char *status_str, const return 0; } - unsigned long value = 0; - sscanf(ptr + strlen(tag), "%lu", &value); + unsigned int value = 0; + sscanf(ptr + strlen(tag), "%u", &value); return (uint32_t)value; } -static bool_t hdhomerun_device_get_tuner_status_lock_is_bcast(struct hdhomerun_tuner_status_t *status) +static bool hdhomerun_device_get_tuner_status_lock_is_bcast(struct hdhomerun_tuner_status_t *status) { if (strcmp(status->lock_str, "8vsb") == 0) { - return TRUE; + return true; } if (strncmp(status->lock_str, "t8", 2) == 0) { - return TRUE; + return true; } if (strncmp(status->lock_str, "t7", 2) == 0) { - return TRUE; + return true; } if (strncmp(status->lock_str, "t6", 2) == 0) { - return TRUE; + return true; } - return FALSE; + return false; } uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status) @@ -467,7 +448,7 @@ int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **psta memset(status, 0, sizeof(struct hdhomerun_tuner_status_t)); char name[32]; - sprintf(name, "/tuner%u/status", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/status", hd->tuner); char *status_str; int ret = hdhomerun_control_get(hd->cs, name, &status_str, NULL); @@ -479,29 +460,140 @@ int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **psta *pstatus_str = status_str; } - char *channel = strstr(status_str, "ch="); - if (channel) { - sscanf(channel + 3, "%31s", status->channel); + if (status) { + char *channel = strstr(status_str, "ch="); + if (channel) { + sscanf(channel + 3, "%31s", status->channel); + } + + char *lock = strstr(status_str, "lock="); + if (lock) { + sscanf(lock + 5, "%31s", status->lock_str); + } + + status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss="); + status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq="); + status->symbol_error_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "seq="); + status->raw_bits_per_second = hdhomerun_device_get_status_parse(status_str, "bps="); + status->packets_per_second = hdhomerun_device_get_status_parse(status_str, "pps="); + + status->signal_present = status->signal_strength >= 45; + + if (strcmp(status->lock_str, "none") != 0) { + if (status->lock_str[0] == '(') { + status->lock_unsupported = true; + } else { + status->lock_supported = true; + } + } + } + + return 1; +} + +int hdhomerun_device_get_oob_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status) +{ + if (!hd->cs) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_oob_status: device not set\n"); + return -1; + } + + memset(status, 0, sizeof(struct hdhomerun_tuner_status_t)); + + char *status_str; + int ret = hdhomerun_control_get(hd->cs, "/oob/status", &status_str, NULL); + if (ret <= 0) { + return ret; + } + + if (pstatus_str) { + *pstatus_str = status_str; + } + + if (status) { + char *channel = strstr(status_str, "ch="); + if (channel) { + sscanf(channel + 3, "%31s", status->channel); + } + + char *lock = strstr(status_str, "lock="); + if (lock) { + sscanf(lock + 5, "%31s", status->lock_str); + } + + status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss="); + status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq="); + status->signal_present = status->signal_strength >= 45; + status->lock_supported = (strcmp(status->lock_str, "none") != 0); + } + + return 1; +} + +int hdhomerun_device_get_tuner_vstatus(struct hdhomerun_device_t *hd, char **pvstatus_str, struct hdhomerun_tuner_vstatus_t *vstatus) +{ + if (!hd->cs) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_vstatus: device not set\n"); + return -1; + } + + memset(vstatus, 0, sizeof(struct hdhomerun_tuner_vstatus_t)); + + char var_name[32]; + hdhomerun_sprintf(var_name, var_name + sizeof(var_name), "/tuner%u/vstatus", hd->tuner); + + char *vstatus_str; + int ret = hdhomerun_control_get(hd->cs, var_name, &vstatus_str, NULL); + if (ret <= 0) { + return ret; } - char *lock = strstr(status_str, "lock="); - if (lock) { - sscanf(lock + 5, "%31s", status->lock_str); + if (pvstatus_str) { + *pvstatus_str = vstatus_str; } - status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss="); - status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq="); - status->symbol_error_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "seq="); - status->raw_bits_per_second = hdhomerun_device_get_status_parse(status_str, "bps="); - status->packets_per_second = hdhomerun_device_get_status_parse(status_str, "pps="); + if (vstatus) { + char *vch = strstr(vstatus_str, "vch="); + if (vch) { + sscanf(vch + 4, "%31s", vstatus->vchannel); + } - status->signal_present = status->signal_strength >= 45; + char *name = strstr(vstatus_str, "name="); + if (name) { + sscanf(name + 5, "%31s", vstatus->name); + } - if (strcmp(status->lock_str, "none") != 0) { - if (status->lock_str[0] == '(') { - status->lock_unsupported = TRUE; - } else { - status->lock_supported = TRUE; + char *auth = strstr(vstatus_str, "auth="); + if (auth) { + sscanf(auth + 5, "%31s", vstatus->auth); + } + + char *cci = strstr(vstatus_str, "cci="); + if (cci) { + sscanf(cci + 4, "%31s", vstatus->cci); + } + + char *cgms = strstr(vstatus_str, "cgms="); + if (cgms) { + sscanf(cgms + 5, "%31s", vstatus->cgms); + } + + if (strncmp(vstatus->auth, "not-subscribed", 14) == 0) { + vstatus->not_subscribed = true; + } + + if (strncmp(vstatus->auth, "error", 5) == 0) { + vstatus->not_available = true; + } + if (strncmp(vstatus->auth, "dialog", 6) == 0) { + vstatus->not_available = true; + } + + if (strncmp(vstatus->cci, "protected", 9) == 0) { + vstatus->copy_protected = true; + } + if (strncmp(vstatus->cgms, "protected", 9) == 0) { + vstatus->copy_protected = true; } } @@ -516,7 +608,7 @@ int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char ** } char name[32]; - sprintf(name, "/tuner%u/streaminfo", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/streaminfo", hd->tuner); return hdhomerun_control_get(hd->cs, name, pstreaminfo, NULL); } @@ -528,10 +620,22 @@ int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pch } char name[32]; - sprintf(name, "/tuner%u/channel", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/channel", hd->tuner); return hdhomerun_control_get(hd->cs, name, pchannel, NULL); } +int hdhomerun_device_get_tuner_vchannel(struct hdhomerun_device_t *hd, char **pvchannel) +{ + if (!hd->cs) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_vchannel: device not set\n"); + return -1; + } + + char name[32]; + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/vchannel", hd->tuner); + return hdhomerun_control_get(hd->cs, name, pvchannel, NULL); +} + int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap) { if (!hd->cs) { @@ -540,7 +644,7 @@ int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char ** } char name[32]; - sprintf(name, "/tuner%u/channelmap", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/channelmap", hd->tuner); return hdhomerun_control_get(hd->cs, name, pchannelmap, NULL); } @@ -552,7 +656,7 @@ int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfil } char name[32]; - sprintf(name, "/tuner%u/filter", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/filter", hd->tuner); return hdhomerun_control_get(hd->cs, name, pfilter, NULL); } @@ -564,7 +668,7 @@ int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **ppr } char name[32]; - sprintf(name, "/tuner%u/program", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/program", hd->tuner); return hdhomerun_control_get(hd->cs, name, pprogram, NULL); } @@ -576,20 +680,12 @@ int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptar } char name[32]; - sprintf(name, "/tuner%u/target", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/target", hd->tuner); return hdhomerun_control_get(hd->cs, name, ptarget, NULL); } -int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount) +static int hdhomerun_device_get_tuner_plotsample_internal(struct hdhomerun_device_t *hd, const char *name, struct hdhomerun_plotsample_t **psamples, size_t *pcount) { - if (!hd->cs) { - hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_plotsample: device not set\n"); - return -1; - } - - char name[32]; - sprintf(name, "/tuner%u/plotsample", hd->tuner); - char *result; int ret = hdhomerun_control_get(hd->cs, name, &result, NULL); if (ret <= 0) { @@ -607,8 +703,8 @@ int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct } *ptr++ = 0; - unsigned long raw; - if (sscanf(result, "%lx", &raw) != 1) { + unsigned int raw; + if (sscanf(result, "%x", &raw) != 1) { break; } @@ -634,36 +730,48 @@ int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct return 1; } -int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner) +int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount) { if (!hd->cs) { - hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_lockkey_owner: device not set\n"); + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_plotsample: device not set\n"); return -1; } char name[32]; - sprintf(name, "/tuner%u/lockkey", hd->tuner); - return hdhomerun_control_get(hd->cs, name, powner, NULL); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/plotsample", hd->tuner); + return hdhomerun_device_get_tuner_plotsample_internal(hd, name, psamples, pcount); } -int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget) +int hdhomerun_device_get_oob_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount) { if (!hd->cs) { - hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_ir_target: device not set\n"); + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_oob_plotsample: device not set\n"); return -1; } - return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL); + return hdhomerun_device_get_tuner_plotsample_internal(hd, "/oob/plotsample", psamples, pcount); } -int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation) +int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner) { if (!hd->cs) { - hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_lineup_location: device not set\n"); + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_lockkey_owner: device not set\n"); return -1; } - return hdhomerun_control_get(hd->cs, "/lineup/location", plocation, NULL); + char name[32]; + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/lockkey", hd->tuner); + return hdhomerun_control_get(hd->cs, name, powner, NULL); +} + +int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget) +{ + if (!hd->cs) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_ir_target: device not set\n"); + return -1; + } + + return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL); } int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num) @@ -684,8 +792,8 @@ int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_ } if (pversion_num) { - unsigned long version_num; - if (sscanf(version_str, "%lu", &version_num) != 1) { + unsigned int version_num; + if (sscanf(version_str, "%u", &version_num) != 1) { *pversion_num = 0; } else { *pversion_num = (uint32_t)version_num; @@ -737,10 +845,22 @@ int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char } char name[32]; - sprintf(name, "/tuner%u/channel", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/channel", hd->tuner); return hdhomerun_control_set_with_lockkey(hd->cs, name, channel, hd->lockkey, NULL, NULL); } +int hdhomerun_device_set_tuner_vchannel(struct hdhomerun_device_t *hd, const char *vchannel) +{ + if (!hd->cs) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_vchannel: device not set\n"); + return -1; + } + + char name[32]; + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/vchannel", hd->tuner); + return hdhomerun_control_set_with_lockkey(hd->cs, name, vchannel, hd->lockkey, NULL, NULL); +} + int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap) { if (!hd->cs) { @@ -749,7 +869,7 @@ int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const c } char name[32]; - sprintf(name, "/tuner%u/channelmap", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/channelmap", hd->tuner); return hdhomerun_control_set_with_lockkey(hd->cs, name, channelmap, hd->lockkey, NULL, NULL); } @@ -761,29 +881,17 @@ int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char } char name[32]; - sprintf(name, "/tuner%u/filter", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/filter", hd->tuner); return hdhomerun_control_set_with_lockkey(hd->cs, name, filter, hd->lockkey, NULL, NULL); } -static int hdhomerun_device_set_tuner_filter_by_array_append(char **pptr, char *end, uint16_t range_begin, uint16_t range_end) +static bool hdhomerun_device_set_tuner_filter_by_array_append(char *ptr, char *end, uint16_t range_begin, uint16_t range_end) { - char *ptr = *pptr; - - size_t available = end - ptr; - size_t required; - if (range_begin == range_end) { - required = snprintf(ptr, available, "0x%04x ", range_begin) + 1; + return hdhomerun_sprintf(ptr, end, "0x%04x ", (unsigned int)range_begin); } else { - required = snprintf(ptr, available, "0x%04x-0x%04x ", range_begin, range_end) + 1; - } - - if (required > available) { - return FALSE; + return hdhomerun_sprintf(ptr, end, "0x%04x-0x%04x ", (unsigned int)range_begin, (unsigned int)range_end); } - - *pptr = strchr(ptr, 0); - return TRUE; } int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000]) @@ -801,9 +909,10 @@ int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, un if (range_begin == 0xFFFF) { continue; } - if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) { + if (!hdhomerun_device_set_tuner_filter_by_array_append(ptr, end, range_begin, range_end)) { return 0; } + ptr = strchr(ptr, 0); range_begin = 0xFFFF; range_end = 0xFFFF; continue; @@ -819,16 +928,17 @@ int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, un } if (range_begin != 0xFFFF) { - if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) { + if (!hdhomerun_device_set_tuner_filter_by_array_append(ptr, end, range_begin, range_end)) { return 0; } + ptr = strchr(ptr, 0); } /* Remove trailing space. */ if (ptr > filter) { ptr--; + *ptr = 0; } - *ptr = 0; return hdhomerun_device_set_tuner_filter(hd, filter); } @@ -841,7 +951,7 @@ int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char } char name[32]; - sprintf(name, "/tuner%u/program", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/program", hd->tuner); return hdhomerun_control_set_with_lockkey(hd->cs, name, program, hd->lockkey, NULL, NULL); } @@ -853,7 +963,7 @@ int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char } char name[32]; - sprintf(name, "/tuner%u/target", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/target", hd->tuner); return hdhomerun_control_set_with_lockkey(hd->cs, name, target, hd->lockkey, NULL, NULL); } @@ -872,7 +982,7 @@ static int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t char target[64]; uint32_t local_ip = hdhomerun_control_get_local_addr(hd->cs); uint16_t local_port = hdhomerun_video_get_local_port(hd->vs); - sprintf(target, "%s://%u.%u.%u.%u:%u", + hdhomerun_sprintf(target, target + sizeof(target), "%s://%u.%u.%u.%u:%u", protocol, (unsigned int)(local_ip >> 24) & 0xFF, (unsigned int)(local_ip >> 16) & 0xFF, (unsigned int)(local_ip >> 8) & 0xFF, (unsigned int)(local_ip >> 0) & 0xFF, @@ -892,16 +1002,6 @@ int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *ta return hdhomerun_control_set(hd->cs, "/ir/target", target, NULL, NULL); } -int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location) -{ - if (!hd->cs) { - hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_lineup_location: device not set\n"); - return -1; - } - - return hdhomerun_control_set(hd->cs, "/lineup/location", location, NULL, NULL); -} - int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list) { if (!hd->cs) { @@ -945,10 +1045,10 @@ int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char * uint32_t new_lockkey = random_get32(); char name[32]; - sprintf(name, "/tuner%u/lockkey", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/lockkey", hd->tuner); char new_lockkey_str[64]; - sprintf(new_lockkey_str, "%u", (unsigned int)new_lockkey); + hdhomerun_sprintf(new_lockkey_str, new_lockkey_str + sizeof(new_lockkey_str), "%u", (unsigned int)new_lockkey); int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, new_lockkey_str, hd->lockkey, NULL, perror); if (ret <= 0) { @@ -975,7 +1075,7 @@ int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd) } char name[32]; - sprintf(name, "/tuner%u/lockkey", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/lockkey", hd->tuner); int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, "none", hd->lockkey, NULL, NULL); hd->lockkey = 0; @@ -993,7 +1093,7 @@ int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd) } char name[32]; - sprintf(name, "/tuner%u/lockkey", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/lockkey", hd->tuner); int ret = hdhomerun_control_set(hd->cs, name, "force", NULL, NULL); hd->lockkey = 0; @@ -1045,6 +1145,8 @@ int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd) return -1; } + hdhomerun_video_set_keepalive(hd->vs, 0, 0, 0); + /* Set target. */ if (hd->multicast_ip != 0) { int ret = hdhomerun_video_join_multicast_group(hd->vs, hd->multicast_ip, 0); @@ -1059,6 +1161,9 @@ int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd) if (ret <= 0) { return ret; } + + uint32_t remote_ip = hdhomerun_control_get_device_ip(hd->cs); + hdhomerun_video_set_keepalive(hd->vs, remote_ip, 5004, hd->lockkey); } /* Flush video buffer. */ @@ -1097,7 +1202,7 @@ void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd) } if (hd->multicast_ip != 0) { - hdhomerun_video_leave_multicast_group(hd->vs); + hdhomerun_video_leave_multicast_group(hd->vs, hd->multicast_ip, 0); } else { hdhomerun_device_set_tuner_target(hd, "none"); } @@ -1126,7 +1231,7 @@ int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct h } int ret = channelscan_advance(hd->scan, result); - if (ret <= 0) { + if (ret <= 0) { /* Free scan if normal finish or fatal error */ channelscan_destroy(hd->scan); hd->scan = NULL; } @@ -1142,7 +1247,7 @@ int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hd } int ret = channelscan_detect(hd->scan, result); - if (ret <= 0) { + if (ret < 0) { /* Free scan if fatal error */ channelscan_destroy(hd->scan); hd->scan = NULL; } @@ -1160,6 +1265,22 @@ uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd) return channelscan_get_progress(hd->scan); } +const char *hdhomerun_device_get_hw_model_str(struct hdhomerun_device_t *hd) +{ + if (!hd->cs) { + hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_hw_model_str: device not set\n"); + return NULL; + } + + char *model_str; + int ret = hdhomerun_control_get(hd->cs, "/sys/hwmodel", &model_str, NULL); + if (ret < 0) { + return NULL; + } + return model_str; +} + + const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd) { if (*hd->model) { @@ -1177,13 +1298,11 @@ const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd) return NULL; } if (ret == 0) { - strncpy(hd->model, "hdhomerun_atsc", sizeof(hd->model) - 1); - hd->model[sizeof(hd->model) - 1] = 0; + hdhomerun_sprintf(hd->model, hd->model + sizeof(hd->model), "hdhomerun_atsc"); return hd->model; } - strncpy(hd->model, model_str, sizeof(hd->model) - 1); - hd->model[sizeof(hd->model) - 1] = 0; + hdhomerun_sprintf(hd->model, hd->model + sizeof(hd->model), "%s", model_str); return hd->model; } @@ -1211,7 +1330,7 @@ void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd) if (hd->cs) { char name[32]; - sprintf(name, "/tuner%u/debug", hd->tuner); + hdhomerun_sprintf(name, name + sizeof(name), "/tuner%u/debug", hd->tuner); char *debug_str; char *error_str; diff --git a/libhdhomerun/hdhomerun_device.h b/libhdhomerun/hdhomerun_device.h index 7fb0f51..6b54ec0 100644 --- a/libhdhomerun/hdhomerun_device.h +++ b/libhdhomerun/hdhomerun_device.h @@ -1,12 +1,12 @@ /* * hdhomerun_device.h * - * Copyright © 2006-2008 Silicondust USA Inc. . + * Copyright © 2006-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus @@ -75,23 +63,25 @@ extern "C" { * * /tuner */ -extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg); -extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg); -extern LIBTYPE void hdhomerun_device_destroy(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create_multicast(uint32_t multicast_ip, uint16_t multicast_port, struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API void hdhomerun_device_destroy(struct hdhomerun_device_t *hd); /* * Get the device id, ip, or tuner of the device instance. */ -extern LIBTYPE const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd); -extern LIBTYPE uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd); -extern LIBTYPE uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd); -extern LIBTYPE uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd); -extern LIBTYPE uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd); -extern LIBTYPE unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd); -extern LIBTYPE int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip); -extern LIBTYPE int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner); -extern LIBTYPE int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str); +extern LIBHDHOMERUN_API int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip); +extern LIBHDHOMERUN_API int hdhomerun_device_set_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip, uint16_t multicast_port); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str); /* * Get the local machine IP address used when communicating with the device. @@ -100,7 +90,7 @@ extern LIBTYPE int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t * * Returns 32-bit IP address with native endianness, or 0 on error. */ -extern LIBTYPE uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd); /* * Get operations. @@ -113,25 +103,29 @@ extern LIBTYPE uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun * Returns 0 if the operation was rejected. * Returns -1 if a communication error occurred. */ -extern LIBTYPE int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status); -extern LIBTYPE int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo); -extern LIBTYPE int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel); -extern LIBTYPE int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap); -extern LIBTYPE int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter); -extern LIBTYPE int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram); -extern LIBTYPE int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget); -extern LIBTYPE int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount); -extern LIBTYPE int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner); -extern LIBTYPE int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget); -extern LIBTYPE int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation); -extern LIBTYPE int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num); -extern LIBTYPE int hdhomerun_device_get_supported(struct hdhomerun_device_t *hd, char *prefix, char **pstr); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_vstatus(struct hdhomerun_device_t *hd, char **pvstatus_str, struct hdhomerun_tuner_vstatus_t *vstatus); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_vchannel(struct hdhomerun_device_t *hd, char **pvchannel); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount); +extern LIBHDHOMERUN_API int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner); +extern LIBHDHOMERUN_API int hdhomerun_device_get_oob_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status); +extern LIBHDHOMERUN_API int hdhomerun_device_get_oob_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount); +extern LIBHDHOMERUN_API int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget); +extern LIBHDHOMERUN_API int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num); +extern LIBHDHOMERUN_API int hdhomerun_device_get_supported(struct hdhomerun_device_t *hd, char *prefix, char **pstr); -extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status); -extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status); -extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_seq_color(struct hdhomerun_tuner_status_t *status); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status); +extern LIBHDHOMERUN_API uint32_t hdhomerun_device_get_tuner_status_seq_color(struct hdhomerun_tuner_status_t *status); -extern LIBTYPE const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API const char *hdhomerun_device_get_hw_model_str(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd); /* * Set operations. @@ -142,15 +136,15 @@ extern LIBTYPE const char *hdhomerun_device_get_model_str(struct hdhomerun_devic * Returns 0 if the operation was rejected. * Returns -1 if a communication error occurred. */ -extern LIBTYPE int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel); -extern LIBTYPE int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap); -extern LIBTYPE int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter); -extern LIBTYPE int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000]); -extern LIBTYPE int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program); -extern LIBTYPE int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target); -extern LIBTYPE int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target); -extern LIBTYPE int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location); -extern LIBTYPE int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_vchannel(struct hdhomerun_device_t *hd, const char *vchannel); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000]); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program); +extern LIBHDHOMERUN_API int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target); +extern LIBHDHOMERUN_API int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target); +extern LIBHDHOMERUN_API int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list); /* * Get/set a named control variable on the device. @@ -169,8 +163,8 @@ extern LIBTYPE int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_dev * Returns 0 if the operation was rejected (pvalue NULL, perror set). * Returns -1 if a communication error occurs. */ -extern LIBTYPE int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror); -extern LIBTYPE int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror); +extern LIBHDHOMERUN_API int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror); +extern LIBHDHOMERUN_API int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror); /* * Tuner locking. @@ -185,14 +179,14 @@ extern LIBTYPE int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const * previously held lock. If locking is used then this function must be called * before destroying the hdhomerun_device object. */ -extern LIBTYPE int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror); -extern LIBTYPE int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd); -extern LIBTYPE int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror); +extern LIBHDHOMERUN_API int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd); /* * Intended only for non persistent connections; eg, hdhomerun_config. */ -extern LIBTYPE void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey); +extern LIBHDHOMERUN_API void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey); /* * Wait for tuner lock after channel change. @@ -204,7 +198,7 @@ extern LIBTYPE void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_de * It will return quickly if there is no signal detected. * Worst case it will time out after 1.5 seconds - the case where there is signal but no lock. */ -extern LIBTYPE int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status); +extern LIBHDHOMERUN_API int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status); /* * Stream a filtered program or the unfiltered stream. @@ -222,18 +216,18 @@ extern LIBTYPE int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, * * The hdhomerun_device_stream_stop function tells the device to stop streaming data. */ -extern LIBTYPE int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd); -extern LIBTYPE uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size); -extern LIBTYPE void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd); -extern LIBTYPE void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size); +extern LIBHDHOMERUN_API void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd); /* * Channel scan API. */ -extern LIBTYPE int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap); -extern LIBTYPE int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result); -extern LIBTYPE int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result); -extern LIBTYPE uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap); +extern LIBHDHOMERUN_API int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result); +extern LIBHDHOMERUN_API int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result); +extern LIBHDHOMERUN_API uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd); /* * Upload new firmware to the device. @@ -244,19 +238,19 @@ extern LIBTYPE uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomeru * Returns 0 if the upload was rejected. * Returns -1 if an error occurs. */ -extern LIBTYPE int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file); +extern LIBHDHOMERUN_API int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file); /* * Low level accessor functions. */ -extern LIBTYPE struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd); -extern LIBTYPE struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd); /* * Debug print internal stats. */ -extern LIBTYPE void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd); -extern LIBTYPE void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats); +extern LIBHDHOMERUN_API void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_device_selector.c b/libhdhomerun/hdhomerun_device_selector.c index ad50fee..2a862ac 100644 --- a/libhdhomerun/hdhomerun_device_selector.c +++ b/libhdhomerun/hdhomerun_device_selector.c @@ -1,12 +1,12 @@ /* * hdhomerun_device_selector.c * - * Copyright © 2009-2010 Silicondust USA Inc. . + * Copyright © 2009-2016 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" @@ -51,7 +39,7 @@ struct hdhomerun_device_selector_t *hdhomerun_device_selector_create(struct hdho return hds; } -void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, bool_t destroy_devices) +void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, bool destroy_devices) { if (destroy_devices) { size_t index; @@ -68,7 +56,7 @@ void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, free(hds); } -LIBTYPE int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds) +int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds) { return (int)hds->hd_count; } @@ -83,12 +71,13 @@ void hdhomerun_device_selector_add_device(struct hdhomerun_device_selector_t *hd } } - hds->hd_list = (struct hdhomerun_device_t **)realloc(hds->hd_list, (hds->hd_count + 1) * sizeof(struct hdhomerun_device_selector_t *)); - if (!hds->hd_list) { + struct hdhomerun_device_t **hd_list = (struct hdhomerun_device_t **)realloc(hds->hd_list, (hds->hd_count + 1) * sizeof(struct hdhomerun_device_t *)); + if (!hd_list) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_add_device: failed to allocate device list\n"); return; } + hds->hd_list = hd_list; hds->hd_list[hds->hd_count++] = hd; } @@ -134,6 +123,123 @@ struct hdhomerun_device_t *hdhomerun_device_selector_find_device(struct hdhomeru return NULL; } +static int hdhomerun_device_selector_load_from_str_discover(struct hdhomerun_device_selector_t *hds, uint32_t target_ip, uint32_t device_id) +{ + struct hdhomerun_discover_device_t result; + int discover_count = hdhomerun_discover_find_devices_custom_v2(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, device_id, &result, 1); + if (discover_count != 1) { + return 0; + } + + int count = 0; + unsigned int tuner_index; + for (tuner_index = 0; tuner_index < result.tuner_count; tuner_index++) { + struct hdhomerun_device_t *hd = hdhomerun_device_create(result.device_id, result.ip_addr, tuner_index, hds->dbg); + if (!hd) { + continue; + } + + hdhomerun_device_selector_add_device(hds, hd); + count++; + } + + return count; +} + +int hdhomerun_device_selector_load_from_str(struct hdhomerun_device_selector_t *hds, char *device_str) +{ + /* + * IP address based device_str. + */ + unsigned int a[4]; + if (sscanf(device_str, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]) == 4) { + uint32_t ip_addr = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0)); + + /* + * Multicast IP address. + */ + unsigned int port; + if (sscanf(device_str, "%u.%u.%u.%u:%u", &a[0], &a[1], &a[2], &a[3], &port) == 5) { + struct hdhomerun_device_t *hd = hdhomerun_device_create_multicast(ip_addr, (uint16_t)port, hds->dbg); + if (!hd) { + return 0; + } + + hdhomerun_device_selector_add_device(hds, hd); + return 1; + } + + /* + * IP address + tuner number. + */ + unsigned int tuner; + if (sscanf(device_str, "%u.%u.%u.%u-%u", &a[0], &a[1], &a[2], &a[3], &tuner) == 5) { + struct hdhomerun_device_t *hd = hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, tuner, hds->dbg); + if (!hd) { + return 0; + } + + hdhomerun_device_selector_add_device(hds, hd); + return 1; + } + + /* + * IP address only - discover and add tuners. + */ + return hdhomerun_device_selector_load_from_str_discover(hds, ip_addr, HDHOMERUN_DEVICE_ID_WILDCARD); + } + + /* + * Device ID based device_str. + */ + char *end; + uint32_t device_id = (uint32_t)strtoul(device_str, &end, 16); + if ((end == device_str + 8) && hdhomerun_discover_validate_device_id(device_id)) { + /* + * IP address + tuner number. + */ + if (*end == '-') { + unsigned int tuner = (unsigned int)strtoul(end + 1, NULL, 10); + struct hdhomerun_device_t *hd = hdhomerun_device_create(device_id, 0, tuner, hds->dbg); + if (!hd) { + return 0; + } + + hdhomerun_device_selector_add_device(hds, hd); + return 1; + } + + /* + * Device ID only - discover and add tuners. + */ + return hdhomerun_device_selector_load_from_str_discover(hds, 0, device_id); + } + + /* + * DNS based device_str. + */ + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + struct addrinfo *sock_info; + if (getaddrinfo(device_str, "65001", &hints, &sock_info) != 0) { + return 0; + } + + struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr; + uint32_t ip_addr = (uint32_t)ntohl(sock_addr->sin_addr.s_addr); + freeaddrinfo(sock_info); + + if (ip_addr == 0) { + return 0; + } + + return hdhomerun_device_selector_load_from_str_discover(hds, ip_addr, HDHOMERUN_DEVICE_ID_WILDCARD); +} + int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename) { FILE *fp = fopen(filename, "r"); @@ -141,25 +247,21 @@ int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t return 0; } + int count = 0; while(1) { - char device_name[32]; - if (!fgets(device_name, sizeof(device_name), fp)) { + char device_str[32]; + if (!fgets(device_str, sizeof(device_str), fp)) { break; } - struct hdhomerun_device_t *hd = hdhomerun_device_create_from_str(device_name, hds->dbg); - if (!hd) { - continue; - } - - hdhomerun_device_selector_add_device(hds, hd); + count += hdhomerun_device_selector_load_from_str(hds, device_str); } fclose(fp); - return (int)hds->hd_count; + return count; } -#if defined(__WINDOWS__) +#if defined(_WIN32) && !defined(_WINRT) int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource) { HKEY tuners_key; @@ -169,21 +271,22 @@ int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device return 0; } + int count = 0; DWORD index = 0; while (1) { /* Next tuner device. */ - wchar_t wdevice_name[32]; - DWORD size = sizeof(wdevice_name); - ret = RegEnumKeyEx(tuners_key, index++, wdevice_name, &size, NULL, NULL, NULL, NULL); + wchar_t wdevice_str[32]; + DWORD size = sizeof(wdevice_str); + ret = RegEnumKeyEx(tuners_key, index++, wdevice_str, &size, NULL, NULL, NULL, NULL); if (ret != ERROR_SUCCESS) { break; } /* Check device configuation. */ HKEY device_key; - ret = RegOpenKeyEx(tuners_key, wdevice_name, 0, KEY_QUERY_VALUE, &device_key); + ret = RegOpenKeyEx(tuners_key, wdevice_str, 0, KEY_QUERY_VALUE, &device_key); if (ret != ERROR_SUCCESS) { - 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); + hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open registry key for %S (%ld)\n", wdevice_str, (long)ret); continue; } @@ -200,39 +303,32 @@ int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device } /* Create and add device. */ - char device_name[32]; - sprintf(device_name, "%S", wdevice_name); - - struct hdhomerun_device_t *hd = hdhomerun_device_create_from_str(device_name, hds->dbg); - if (!hd) { - hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: invalid device name '%s' / failed to create device object\n", device_name); - continue; - } - - hdhomerun_device_selector_add_device(hds, hd); + char device_str[32]; + hdhomerun_sprintf(device_str, device_str + sizeof(device_str), "%S", wdevice_str); + count += hdhomerun_device_selector_load_from_str(hds, device_str); } RegCloseKey(tuners_key); - return (int)hds->hd_count; + return count; } #endif -static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *test_hd) +static bool hdhomerun_device_selector_choose_test(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *test_hd) { const char *name = hdhomerun_device_get_name(test_hd); /* * Attempt to aquire lock. */ - char *error; + char *error = NULL; int ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error); if (ret > 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name); - return TRUE; + return true; } if (ret < 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name); - return FALSE; + return false; } /* @@ -242,51 +338,52 @@ static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_sele ret = hdhomerun_device_get_tuner_target(test_hd, &target); if (ret < 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name); - return FALSE; + return false; } if (ret == 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to read target\n", name); - return FALSE; + return false; } - char *ptr = strstr(target, "//"); - if (ptr) { - target = ptr + 2; + if (strcmp(target, "none") == 0) { + hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, no target set\n", name); + return false; } - ptr = strchr(target, ' '); - if (ptr) { - *ptr = 0; + + if ((strncmp(target, "udp://", 6) != 0) && (strncmp(target, "rtp://", 6) != 0)) { + hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by %s\n", name, target); + return false; } - unsigned long a[4]; - unsigned long target_port; - if (sscanf(target, "%lu.%lu.%lu.%lu:%lu", &a[0], &a[1], &a[2], &a[3], &target_port) != 5) { - hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, no target set (%s)\n", name, target); - return FALSE; + unsigned int a[4]; + unsigned int target_port; + if (sscanf(target + 6, "%u.%u.%u.%u:%u", &a[0], &a[1], &a[2], &a[3], &target_port) != 5) { + hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, unexpected target set (%s)\n", name, target); + return false; } uint32_t target_ip = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0)); uint32_t local_ip = hdhomerun_device_get_local_machine_addr(test_hd); if (target_ip != local_ip) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by %s\n", name, target); - return FALSE; + return false; } /* * Test local port. */ - hdhomerun_sock_t test_sock = hdhomerun_sock_create_udp(); - if (test_sock == HDHOMERUN_SOCK_INVALID) { + struct hdhomerun_sock_t *test_sock = hdhomerun_sock_create_udp(); + if (!test_sock) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to create test sock\n", name); - return FALSE; + return false; } - bool_t inuse = (hdhomerun_sock_bind(test_sock, INADDR_ANY, (uint16_t)target_port) == FALSE); + bool inuse = (hdhomerun_sock_bind(test_sock, INADDR_ANY, (uint16_t)target_port, false) == false); hdhomerun_sock_destroy(test_sock); if (inuse) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine\n", name); - return FALSE; + return false; } /* @@ -295,11 +392,11 @@ static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_sele ret = hdhomerun_device_tuner_lockkey_force(test_hd); if (ret < 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name); - return FALSE; + return false; } if (ret == 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, failed to force release lockkey\n", name); - return FALSE; + return false; } hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, lockkey force successful\n", name); @@ -310,15 +407,15 @@ static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_sele ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error); if (ret > 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name); - return TRUE; + return true; } if (ret < 0) { hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name); - return FALSE; + return false; } hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s still in use after lockkey force (%s)\n", name, error); - return FALSE; + return false; } struct hdhomerun_device_t *hdhomerun_device_selector_choose_and_lock(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *prefered) diff --git a/libhdhomerun/hdhomerun_device_selector.h b/libhdhomerun/hdhomerun_device_selector.h index 2f3587c..7f3bed6 100644 --- a/libhdhomerun/hdhomerun_device_selector.h +++ b/libhdhomerun/hdhomerun_device_selector.h @@ -1,12 +1,12 @@ /* * hdhomerun_device_selector.h * - * Copyright © 2009 Silicondust USA Inc. . + * Copyright © 2009-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus @@ -39,33 +27,35 @@ extern "C" { * All tuners registered with a specific device selector instance must have the same signal source. * The dbg parameter may be null. */ -extern LIBTYPE struct hdhomerun_device_selector_t *hdhomerun_device_selector_create(struct hdhomerun_debug_t *dbg); -extern LIBTYPE void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, bool_t destroy_devices); +extern LIBHDHOMERUN_API struct hdhomerun_device_selector_t *hdhomerun_device_selector_create(struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, bool destroy_devices); /* * Get the number of devices in the list. */ -extern LIBTYPE int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds); +extern LIBHDHOMERUN_API int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds); /* * Populate device selector with devices from given source. * Returns the number of devices populated. */ -extern LIBTYPE int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename); -#if defined(__WINDOWS__) -extern LIBTYPE int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource); +extern LIBHDHOMERUN_API int hdhomerun_device_selector_load_from_str(struct hdhomerun_device_selector_t *hds, char *device_str); +extern LIBHDHOMERUN_API int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename); + +#if defined(_WIN32) && !defined(_WINRT) +extern LIBHDHOMERUN_API int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource); #endif /* * Add/remove a device from the selector list. */ -extern LIBTYPE void hdhomerun_device_selector_add_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd); -extern LIBTYPE void hdhomerun_device_selector_remove_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API void hdhomerun_device_selector_add_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd); +extern LIBHDHOMERUN_API void hdhomerun_device_selector_remove_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd); /* * Find a device in the selector list. */ -extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_selector_find_device(struct hdhomerun_device_selector_t *hds, uint32_t device_id, unsigned int tuner_index); +extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_selector_find_device(struct hdhomerun_device_selector_t *hds, uint32_t device_id, unsigned int tuner_index); /* * Select and lock an available device. @@ -90,7 +80,7 @@ extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_selector_find_device( * to refresh the lock. If this function succeeds then the same device can be used. If this fucntion fails * then call hdhomerun_device_selector_choose_and_lock() to choose and lock an available tuner. */ -extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_selector_choose_and_lock(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *prefered); +extern LIBHDHOMERUN_API struct hdhomerun_device_t *hdhomerun_device_selector_choose_and_lock(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *prefered); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_discover.c b/libhdhomerun/hdhomerun_discover.c index 27816b2..11c6ed5 100644 --- a/libhdhomerun/hdhomerun_discover.c +++ b/libhdhomerun/hdhomerun_discover.c @@ -1,12 +1,12 @@ /* * hdhomerun_discover.c * - * Copyright © 2006-2010 Silicondust USA Inc. . + * Copyright © 2006-2017 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,97 +14,78 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" -#if defined(__CYGWIN__) || defined(__WINDOWS__) -#include -#include -#define USE_IPHLPAPI 1 -#else -#include -#include -#ifndef _SIZEOF_ADDR_IFREQ -#define _SIZEOF_ADDR_IFREQ(x) sizeof(x) -#endif -#endif - -#define HDHOMERUN_DISOCVER_MAX_SOCK_COUNT 16 +#define HDHOMERUN_DISCOVER_MAX_SOCK_COUNT 16 struct hdhomerun_discover_sock_t { - hdhomerun_sock_t sock; - bool_t detected; + struct hdhomerun_sock_t *sock; + bool detected; uint32_t local_ip; uint32_t subnet_mask; }; struct hdhomerun_discover_t { - struct hdhomerun_discover_sock_t socks[HDHOMERUN_DISOCVER_MAX_SOCK_COUNT]; + struct hdhomerun_discover_sock_t socks[HDHOMERUN_DISCOVER_MAX_SOCK_COUNT]; unsigned int sock_count; struct hdhomerun_pkt_t tx_pkt; struct hdhomerun_pkt_t rx_pkt; + struct hdhomerun_debug_t *dbg; }; -static bool_t hdhomerun_discover_sock_add(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask) +static bool hdhomerun_discover_sock_add(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask) { unsigned int i; for (i = 1; i < ds->sock_count; i++) { struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; if ((dss->local_ip == local_ip) && (dss->subnet_mask == subnet_mask)) { - dss->detected = TRUE; - return TRUE; + dss->detected = true; + return true; } } - if (ds->sock_count >= HDHOMERUN_DISOCVER_MAX_SOCK_COUNT) { - return FALSE; + if (ds->sock_count >= HDHOMERUN_DISCOVER_MAX_SOCK_COUNT) { + return false; } /* Create socket. */ - hdhomerun_sock_t sock = hdhomerun_sock_create_udp(); - if (sock == HDHOMERUN_SOCK_INVALID) { - return FALSE; + struct hdhomerun_sock_t *sock = hdhomerun_sock_create_udp(); + if (!sock) { + hdhomerun_debug_printf(ds->dbg, "discover: failed to allocate socket (%d)\n", hdhomerun_sock_getlasterror()); + return false; } /* Bind socket. */ - if (!hdhomerun_sock_bind(sock, local_ip, 0)) { + if (!hdhomerun_sock_bind(sock, local_ip, 0, false)) { + hdhomerun_debug_printf(ds->dbg, "discover: failed to bind to %u.%u.%u.%u:0\n", (unsigned int)(local_ip >> 24) & 0xFF, (unsigned int)(local_ip >> 16) & 0xFF, (unsigned int)(local_ip >> 8) & 0xFF, (unsigned int)(local_ip >> 0) & 0xFF); hdhomerun_sock_destroy(sock); - return FALSE; + return false; } /* Write sock entry. */ struct hdhomerun_discover_sock_t *dss = &ds->socks[ds->sock_count++]; dss->sock = sock; - dss->detected = TRUE; + dss->detected = true; dss->local_ip = local_ip; dss->subnet_mask = subnet_mask; - return TRUE; + return true; } -struct hdhomerun_discover_t *hdhomerun_discover_create(void) +struct hdhomerun_discover_t *hdhomerun_discover_create(struct hdhomerun_debug_t *dbg) { struct hdhomerun_discover_t *ds = (struct hdhomerun_discover_t *)calloc(1, sizeof(struct hdhomerun_discover_t)); if (!ds) { return NULL; } + ds->dbg = dbg; + /* Create a routable socket (always first entry). */ if (!hdhomerun_discover_sock_add(ds, 0, 0)) { free(ds); @@ -126,105 +107,34 @@ void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds) free(ds); } -#if defined(USE_IPHLPAPI) -static void hdhomerun_discover_sock_detect_internal(struct hdhomerun_discover_t *ds) -{ - PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO)); - ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); - - DWORD Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); - if (Ret != NO_ERROR) { - free(pAdapterInfo); - if (Ret != ERROR_BUFFER_OVERFLOW) { - return; - } - pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); - Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); - if (Ret != NO_ERROR) { - free(pAdapterInfo); - return; - } - } - - PIP_ADAPTER_INFO pAdapter = pAdapterInfo; - while (pAdapter) { - IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; - while (pIPAddr) { - uint32_t local_ip = ntohl(inet_addr(pIPAddr->IpAddress.String)); - uint32_t mask = ntohl(inet_addr(pIPAddr->IpMask.String)); - - if (local_ip == 0) { - pIPAddr = pIPAddr->Next; - continue; - } - - hdhomerun_discover_sock_add(ds, local_ip, mask); - pIPAddr = pIPAddr->Next; - } - - pAdapter = pAdapter->Next; - } - - free(pAdapterInfo); -} - -#else - -static void hdhomerun_discover_sock_detect_internal(struct hdhomerun_discover_t *ds) -{ - int sock = ds->socks[0].sock; - - struct ifconf ifc; - uint8_t buf[8192]; - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = (char *)buf; - - memset(buf, 0, sizeof(buf)); - - if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) { - return; - } - - uint8_t *ptr = (uint8_t *)ifc.ifc_req; - uint8_t *end = (uint8_t *)&ifc.ifc_buf[ifc.ifc_len]; - - while (ptr <= end) { - struct ifreq *ifr = (struct ifreq *)ptr; - ptr += _SIZEOF_ADDR_IFREQ(*ifr); - - if (ioctl(sock, SIOCGIFADDR, ifr) != 0) { - continue; - } - struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr); - uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr); - if (local_ip == 0) { - continue; - } - - if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) { - continue; - } - struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr); - uint32_t mask = ntohl(mask_in->sin_addr.s_addr); - - hdhomerun_discover_sock_add(ds, local_ip, mask); - } -} -#endif - static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds) { unsigned int i; for (i = 1; i < ds->sock_count; i++) { struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; - dss->detected = FALSE; + dss->detected = false; + } + + struct hdhomerun_local_ip_info_t ip_info_list[HDHOMERUN_DISCOVER_MAX_SOCK_COUNT]; + int count = hdhomerun_local_ip_info(ip_info_list, HDHOMERUN_DISCOVER_MAX_SOCK_COUNT); + if (count < 0) { + hdhomerun_debug_printf(ds->dbg, "discover: hdhomerun_local_ip_info returned error\n"); + count = 0; + } + if (count > HDHOMERUN_DISCOVER_MAX_SOCK_COUNT) { + hdhomerun_debug_printf(ds->dbg, "discover: too many local IP addresses\n"); + count = HDHOMERUN_DISCOVER_MAX_SOCK_COUNT; } - hdhomerun_discover_sock_detect_internal(ds); + int index; + for (index = 0; index < count; index++) { + struct hdhomerun_local_ip_info_t *ip_info = &ip_info_list[index]; + hdhomerun_discover_sock_add(ds, ip_info->ip_addr, ip_info->subnet_mask); + } struct hdhomerun_discover_sock_t *src = &ds->socks[1]; struct hdhomerun_discover_sock_t *dst = &ds->socks[1]; - unsigned int count = 1; + count = 1; for (i = 1; i < ds->sock_count; i++) { if (!src->detected) { hdhomerun_sock_destroy(src->sock); @@ -239,10 +149,10 @@ static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds) count++; } - ds->sock_count = count; + ds->sock_count = (unsigned int)count; } -static bool_t hdhomerun_discover_send_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, uint32_t target_ip, uint32_t device_type, uint32_t device_id) +static bool 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) { struct hdhomerun_pkt_t *tx_pkt = &ds->tx_pkt; hdhomerun_pkt_reset(tx_pkt); @@ -258,9 +168,9 @@ static bool_t hdhomerun_discover_send_internal(struct hdhomerun_discover_t *ds, return hdhomerun_sock_sendto(dss->sock, target_ip, HDHOMERUN_DISCOVER_UDP_PORT, tx_pkt->start, tx_pkt->end - tx_pkt->start, 0); } -static bool_t hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id) +static bool hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id) { - bool_t result = FALSE; + bool result = false; /* * Send subnet broadcast using each local ip socket. @@ -284,9 +194,9 @@ static bool_t hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *d return result; } -static bool_t hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) +static bool hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) { - bool_t result = FALSE; + bool result = false; /* * Send targeted packet from any local ip that is in the same subnet. @@ -295,6 +205,9 @@ static bool_t hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, unsigned int i; for (i = 1; i < ds->sock_count; i++) { struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; + if (dss->subnet_mask == 0) { + continue; + } if ((target_ip & dss->subnet_mask) != (dss->local_ip & dss->subnet_mask)) { continue; } @@ -313,7 +226,7 @@ static bool_t hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, return result; } -static bool_t hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) +static bool hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id) { if (target_ip == 0) { return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id); @@ -322,8 +235,31 @@ static bool_t hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t } } -static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result) +static bool hdhomerun_discover_is_legacy(uint32_t device_id) { + switch (device_id >> 20) { + case 0x100: /* TECH-US/TECH3-US */ + return (device_id < 0x10040000); + + case 0x120: /* TECH3-EU */ + return (device_id < 0x12030000); + + case 0x101: /* HDHR-US */ + case 0x102: /* HDHR-T1-US */ + case 0x103: /* HDHR3-US */ + case 0x111: /* HDHR3-DT */ + case 0x121: /* HDHR-EU */ + case 0x122: /* HDHR3-EU */ + return true; + + default: + return false; + } +} + +static bool hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result) +{ + static char hdhomerun_discover_recv_base64_encode_table[64 + 1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; struct hdhomerun_pkt_t *rx_pkt = &ds->rx_pkt; hdhomerun_pkt_reset(rx_pkt); @@ -331,22 +267,25 @@ static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, uint16_t remote_port; size_t length = rx_pkt->limit - rx_pkt->end; if (!hdhomerun_sock_recvfrom(dss->sock, &remote_addr, &remote_port, rx_pkt->end, &length, 0)) { - return FALSE; + return false; } rx_pkt->end += length; uint16_t type; if (hdhomerun_pkt_open_frame(rx_pkt, &type) <= 0) { - return FALSE; + return false; } if (type != HDHOMERUN_TYPE_DISCOVER_RPY) { - return FALSE; + return false; } + memset(result, 0, sizeof(struct hdhomerun_discover_device_t)); result->ip_addr = remote_addr; - result->device_type = 0; - result->device_id = 0; + + hdhomerun_sprintf(result->base_url, result->base_url + sizeof(result->base_url), "http://%u.%u.%u.%u:80", + (remote_addr >> 24) & 0xFF, (remote_addr >> 16) & 0xFF, (remote_addr >> 8) & 0xFF, (remote_addr >> 0) & 0xFF + ); while (1) { uint8_t tag; @@ -356,6 +295,7 @@ static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, break; } + int i; switch (tag) { case HDHOMERUN_TAG_DEVICE_TYPE: if (len != 4) { @@ -369,6 +309,47 @@ static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, break; } result->device_id = hdhomerun_pkt_read_u32(rx_pkt); + result->is_legacy = hdhomerun_discover_is_legacy(result->device_id); + break; + + case HDHOMERUN_TAG_TUNER_COUNT: + if (len != 1) { + break; + } + result->tuner_count = hdhomerun_pkt_read_u8(rx_pkt); + break; + + case HDHOMERUN_TAG_DEVICE_AUTH_STR: + if (len >= sizeof(result->device_auth)) { + break; + } + hdhomerun_pkt_read_mem(rx_pkt, result->device_auth, len); + result->device_auth[len] = 0; + break; + + case HDHOMERUN_TAG_DEVICE_AUTH_BIN: + if (len != 18) { + break; + } + for (i = 0; i < 24; i += 4) { + uint32_t raw24; + raw24 = (uint32_t)hdhomerun_pkt_read_u8(rx_pkt) << 16; + raw24 |= (uint32_t)hdhomerun_pkt_read_u8(rx_pkt) << 8; + raw24 |= (uint32_t)hdhomerun_pkt_read_u8(rx_pkt) << 0; + result->device_auth[i + 0] = hdhomerun_discover_recv_base64_encode_table[(raw24 >> 18) & 0x3F]; + result->device_auth[i + 1] = hdhomerun_discover_recv_base64_encode_table[(raw24 >> 12) & 0x3F]; + result->device_auth[i + 2] = hdhomerun_discover_recv_base64_encode_table[(raw24 >> 6) & 0x3F]; + result->device_auth[i + 3] = hdhomerun_discover_recv_base64_encode_table[(raw24 >> 0) & 0x3F]; + } + result->device_auth[24] = 0; + break; + + case HDHOMERUN_TAG_BASE_URL: + if (len >= sizeof(result->base_url)) { + break; + } + hdhomerun_pkt_read_mem(rx_pkt, result->base_url, len); + result->base_url[len] = 0; break; default: @@ -378,21 +359,39 @@ static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, rx_pkt->pos = next; } - return TRUE; + /* Fixup for old firmware. */ + if (result->tuner_count == 0) { + switch (result->device_id >> 20) { + case 0x102: + result->tuner_count = 1; + break; + + case 0x100: + case 0x101: + case 0x121: + result->tuner_count = 2; + break; + + default: + break; + } + } + + return true; } -static bool_t hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result) +static bool hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result) { unsigned int i; for (i = 0; i < ds->sock_count; i++) { struct hdhomerun_discover_sock_t *dss = &ds->socks[i]; if (hdhomerun_discover_recv_internal(ds, dss, result)) { - return TRUE; + return true; } } - return FALSE; + return false; } static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struct hdhomerun_discover_device_t result_list[], int count, struct hdhomerun_discover_device_t *lookup) @@ -408,7 +407,7 @@ static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struc return NULL; } -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) +int hdhomerun_discover_find_devices_v2(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) { hdhomerun_discover_sock_detect(ds); @@ -422,12 +421,13 @@ int hdhomerun_discover_find_devices(struct hdhomerun_discover_t *ds, uint32_t ta uint64_t timeout = getcurrenttime() + 200; while (1) { struct hdhomerun_discover_device_t *result = &result_list[count]; + memset(result, 0, sizeof(struct hdhomerun_discover_device_t)); if (!hdhomerun_discover_recv(ds, result)) { if (getcurrenttime() >= timeout) { break; } - msleep_approx(10); + msleep_approx(16); continue; } @@ -459,28 +459,28 @@ int hdhomerun_discover_find_devices(struct hdhomerun_discover_t *ds, uint32_t ta return count; } -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) +int hdhomerun_discover_find_devices_custom_v2(uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count) { if (hdhomerun_discover_is_ip_multicast(target_ip)) { return 0; } - struct hdhomerun_discover_t *ds = hdhomerun_discover_create(); + struct hdhomerun_discover_t *ds = hdhomerun_discover_create(NULL); if (!ds) { return -1; } - int ret = hdhomerun_discover_find_devices(ds, target_ip, device_type, device_id, result_list, max_count); + int ret = hdhomerun_discover_find_devices_v2(ds, target_ip, device_type, device_id, result_list, max_count); hdhomerun_discover_destroy(ds); return ret; } -bool_t hdhomerun_discover_validate_device_id(uint32_t device_id) +bool hdhomerun_discover_validate_device_id(uint32_t device_id) { - static uint32_t lookup_table[16] = {0xA, 0x5, 0xF, 0x6, 0x7, 0xC, 0x1, 0xB, 0x9, 0x2, 0x8, 0xD, 0x4, 0x3, 0xE, 0x0}; + static uint8_t lookup_table[16] = {0xA, 0x5, 0xF, 0x6, 0x7, 0xC, 0x1, 0xB, 0x9, 0x2, 0x8, 0xD, 0x4, 0x3, 0xE, 0x0}; - uint32_t checksum = 0; + uint8_t checksum = 0; checksum ^= lookup_table[(device_id >> 28) & 0x0F]; checksum ^= (device_id >> 24) & 0x0F; @@ -494,7 +494,7 @@ bool_t hdhomerun_discover_validate_device_id(uint32_t device_id) return (checksum == 0); } -bool_t hdhomerun_discover_is_ip_multicast(uint32_t ip_addr) +bool hdhomerun_discover_is_ip_multicast(uint32_t ip_addr) { return (ip_addr >= 0xE0000000) && (ip_addr < 0xF0000000); } diff --git a/libhdhomerun/hdhomerun_discover.h b/libhdhomerun/hdhomerun_discover.h index f85b8fe..c929814 100644 --- a/libhdhomerun/hdhomerun_discover.h +++ b/libhdhomerun/hdhomerun_discover.h @@ -1,12 +1,12 @@ /* * hdhomerun_discover.h * - * Copyright © 2006-2007 Silicondust USA Inc. . + * Copyright © 2006-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus extern "C" { @@ -37,6 +25,10 @@ struct hdhomerun_discover_device_t { uint32_t ip_addr; uint32_t device_type; uint32_t device_id; + uint8_t tuner_count; + bool is_legacy; + char device_auth[25]; + char base_url[29]; }; /* @@ -53,14 +45,14 @@ struct hdhomerun_discover_device_t { * Returns the number of devices found. * Retruns -1 on error. */ -extern LIBTYPE int hdhomerun_discover_find_devices_custom(uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count); +extern LIBHDHOMERUN_API int hdhomerun_discover_find_devices_custom_v2(uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count); /* * Optional: persistent discover instance available for discover polling use. */ -extern LIBTYPE struct hdhomerun_discover_t *hdhomerun_discover_create(void); -extern LIBTYPE void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds); -extern LIBTYPE int hdhomerun_discover_find_devices(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count); +extern LIBHDHOMERUN_API struct hdhomerun_discover_t *hdhomerun_discover_create(struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds); +extern LIBHDHOMERUN_API int hdhomerun_discover_find_devices_v2(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count); /* * Verify that the device ID given is valid. @@ -68,18 +60,18 @@ extern LIBTYPE int hdhomerun_discover_find_devices(struct hdhomerun_discover_t * * The device ID contains a self-check sequence that detects common user input errors including * single-digit errors and two digit transposition errors. * - * Returns TRUE if valid. - * Returns FALSE if not valid. + * Returns true if valid. + * Returns false if not valid. */ -extern LIBTYPE bool_t hdhomerun_discover_validate_device_id(uint32_t device_id); +extern LIBHDHOMERUN_API bool hdhomerun_discover_validate_device_id(uint32_t device_id); /* * Detect if an IP address is multicast. * - * Returns TRUE if multicast. - * Returns FALSE if zero, unicast, expermental, or broadcast. + * Returns true if multicast. + * Returns false if zero, unicast, expermental, or broadcast. */ -extern LIBTYPE bool_t hdhomerun_discover_is_ip_multicast(uint32_t ip_addr); +extern LIBHDHOMERUN_API bool hdhomerun_discover_is_ip_multicast(uint32_t ip_addr); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_os.h b/libhdhomerun/hdhomerun_os.h index 1506e07..07d4ace 100644 --- a/libhdhomerun/hdhomerun_os.h +++ b/libhdhomerun/hdhomerun_os.h @@ -1,12 +1,12 @@ /* * hdhomerun_os.h * - * Copyright © 2006-2008 Silicondust USA Inc. . + * Copyright © 2006-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,36 +14,12 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#if defined(_WIN32) || defined(_WIN64) -#define __WINDOWS__ -#endif - -#if defined(__WINDOWS__) +#if defined(_WIN32) #include "hdhomerun_os_windows.h" #else #include "hdhomerun_os_posix.h" #endif - -#if !defined(TRUE) -#define TRUE 1 -#endif - -#if !defined(FALSE) -#define FALSE 0 -#endif diff --git a/libhdhomerun/hdhomerun_os_posix.c b/libhdhomerun/hdhomerun_os_posix.c new file mode 100644 index 0000000..25c7944 --- /dev/null +++ b/libhdhomerun/hdhomerun_os_posix.c @@ -0,0 +1,262 @@ +/* + * hdhomerun_os_posix.c + * + * Copyright © 2006-2017 Silicondust USA Inc. . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hdhomerun_os.h" + +#if defined(__APPLE__) + +#include +#include + +static pthread_once_t clock_monotonic_once = PTHREAD_ONCE_INIT; +static clock_serv_t clock_monotonic_clock_serv; + +static void clock_monotonic_init(void) +{ + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clock_monotonic_clock_serv); +} + +static inline void clock_monotonic_timespec(struct timespec *ts) +{ + pthread_once(&clock_monotonic_once, clock_monotonic_init); + + struct mach_timespec mt; + clock_get_time(clock_monotonic_clock_serv, &mt); + ts->tv_nsec = mt.tv_nsec; + ts->tv_sec = mt.tv_sec; +} + +static inline void clock_realtime_timespec(struct timespec *ts) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_nsec = tv.tv_usec * 1000; + ts->tv_sec = tv.tv_sec; +} + +#else + +static inline void clock_monotonic_timespec(struct timespec *ts) +{ + clock_gettime(CLOCK_MONOTONIC, ts); +} + +static inline void clock_realtime_timespec(struct timespec *ts) +{ + clock_gettime(CLOCK_REALTIME, ts); +} + +#endif + +static pthread_once_t random_get32_once = PTHREAD_ONCE_INIT; +static FILE *random_get32_fp = NULL; + +static void random_get32_init(void) +{ + random_get32_fp = fopen("/dev/urandom", "rb"); +} + +uint32_t random_get32(void) +{ + pthread_once(&random_get32_once, random_get32_init); + + if (!random_get32_fp) { + return (uint32_t)getcurrenttime(); + } + + uint32_t Result; + if (fread(&Result, 4, 1, random_get32_fp) != 1) { + return (uint32_t)getcurrenttime(); + } + + return Result; +} + +uint64_t getcurrenttime(void) +{ + struct timespec ts; + clock_monotonic_timespec(&ts); + return ((uint64_t)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); +} + +void msleep_approx(uint64_t ms) +{ + uint64_t delay_s = ms / 1000; + if (delay_s > 0) { + sleep((unsigned int)delay_s); + ms -= delay_s * 1000; + } + + uint64_t delay_us = ms * 1000; + if (delay_us > 0) { + usleep((useconds_t)delay_us); + } +} + +void msleep_minimum(uint64_t ms) +{ + uint64_t stop_time = getcurrenttime() + ms; + + while (1) { + uint64_t current_time = getcurrenttime(); + if (current_time >= stop_time) { + return; + } + + msleep_approx(stop_time - current_time); + } +} + +struct thread_task_execute_args_t { + thread_task_func_t func; + void *arg; +}; + +static void *thread_task_execute(void *arg) +{ + struct thread_task_execute_args_t *execute_args = (struct thread_task_execute_args_t *)arg; + execute_args->func(execute_args->arg); + free(execute_args); + return NULL; +} + +bool thread_task_create(thread_task_t *tid, thread_task_func_t func, void *arg) +{ + struct thread_task_execute_args_t *execute_args = (struct thread_task_execute_args_t *)malloc(sizeof(struct thread_task_execute_args_t)); + if (!execute_args) { + return false; + } + + execute_args->func = func; + execute_args->arg = arg; + + if (pthread_create(tid, NULL, thread_task_execute, execute_args) != 0) { + free(execute_args); + return false; + } + + return true; +} + +void thread_task_join(thread_task_t tid) +{ + pthread_join(tid, NULL); +} + +void thread_mutex_init(thread_mutex_t *mutex) +{ + pthread_mutex_init(mutex, NULL); +} + +void thread_mutex_dispose(pthread_mutex_t *mutex) +{ +} + +void thread_mutex_lock(thread_mutex_t *mutex) +{ + pthread_mutex_lock(mutex); +} + +void thread_mutex_unlock(thread_mutex_t *mutex) +{ + pthread_mutex_unlock(mutex); +} + +void thread_cond_init(thread_cond_t *cond) +{ + cond->signaled = false; + pthread_mutex_init(&cond->lock, NULL); + pthread_cond_init(&cond->cond, NULL); +} + +void thread_cond_dispose(thread_cond_t *cond) +{ +} + +void thread_cond_signal(thread_cond_t *cond) +{ + pthread_mutex_lock(&cond->lock); + + cond->signaled = true; + pthread_cond_signal(&cond->cond); + + pthread_mutex_unlock(&cond->lock); +} + +void thread_cond_wait(thread_cond_t *cond) +{ + pthread_mutex_lock(&cond->lock); + + if (!cond->signaled) { + pthread_cond_wait(&cond->cond, &cond->lock); + } + + cond->signaled = false; + pthread_mutex_unlock(&cond->lock); +} + +void thread_cond_wait_with_timeout(thread_cond_t *cond, uint64_t max_wait_time) +{ + pthread_mutex_lock(&cond->lock); + + if (!cond->signaled) { + struct timespec ts; + clock_realtime_timespec(&ts); + + uint64_t tv_nsec = (uint64_t)ts.tv_nsec + (max_wait_time * 1000000); + ts.tv_nsec = (long)(tv_nsec % 1000000000); + ts.tv_sec += (time_t)(tv_nsec / 1000000000); + + pthread_cond_timedwait(&cond->cond, &cond->lock, &ts); + } + + cond->signaled = false; + pthread_mutex_unlock(&cond->lock); +} + +bool hdhomerun_vsprintf(char *buffer, char *end, const char *fmt, va_list ap) +{ + if (buffer >= end) { + return false; + } + + int length = vsnprintf(buffer, end - buffer - 1, fmt, ap); + if (length < 0) { + *buffer = 0; + return false; + } + + if (buffer + length + 1 > end) { + *(end - 1) = 0; + return false; + + } + + return true; +} + +bool hdhomerun_sprintf(char *buffer, char *end, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + bool result = hdhomerun_vsprintf(buffer, end, fmt, ap); + va_end(ap); + return result; +} diff --git a/libhdhomerun/hdhomerun_os_posix.h b/libhdhomerun/hdhomerun_os_posix.h new file mode 100644 index 0000000..386ff13 --- /dev/null +++ b/libhdhomerun/hdhomerun_os_posix.h @@ -0,0 +1,84 @@ +/* + * hdhomerun_os_posix.h + * + * Copyright © 2006-2017 Silicondust USA Inc. . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _FILE_OFFSET_BITS 64 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef void (*sig_t)(int); +typedef void (*thread_task_func_t)(void *arg); +typedef pthread_t thread_task_t; +typedef pthread_mutex_t thread_mutex_t; + +typedef struct { + volatile bool signaled; + pthread_mutex_t lock; + pthread_cond_t cond; +} thread_cond_t; + +#define LIBHDHOMERUN_API + +#ifdef __cplusplus +extern "C" { +#endif + +extern LIBHDHOMERUN_API uint32_t random_get32(void); +extern LIBHDHOMERUN_API uint64_t getcurrenttime(void); +extern LIBHDHOMERUN_API void msleep_approx(uint64_t ms); +extern LIBHDHOMERUN_API void msleep_minimum(uint64_t ms); + +extern LIBHDHOMERUN_API bool thread_task_create(thread_task_t *tid, thread_task_func_t func, void *arg); +extern LIBHDHOMERUN_API void thread_task_join(thread_task_t tid); + +extern LIBHDHOMERUN_API void thread_mutex_init(thread_mutex_t *mutex); +extern LIBHDHOMERUN_API void thread_mutex_dispose(thread_mutex_t *mutex); +extern LIBHDHOMERUN_API void thread_mutex_lock(thread_mutex_t *mutex); +extern LIBHDHOMERUN_API void thread_mutex_unlock(thread_mutex_t *mutex); + +extern LIBHDHOMERUN_API void thread_cond_init(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_dispose(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_signal(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_wait(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_wait_with_timeout(thread_cond_t *cond, uint64_t max_wait_time); + +extern LIBHDHOMERUN_API bool hdhomerun_vsprintf(char *buffer, char *end, const char *fmt, va_list ap); +extern LIBHDHOMERUN_API bool hdhomerun_sprintf(char *buffer, char *end, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif diff --git a/libhdhomerun/hdhomerun_os_windows.c b/libhdhomerun/hdhomerun_os_windows.c index 5f844db..ea65945 100644 --- a/libhdhomerun/hdhomerun_os_windows.c +++ b/libhdhomerun/hdhomerun_os_windows.c @@ -1,12 +1,12 @@ /* * hdhomerun_os_windows.c * - * Copyright © 2006-2010 Silicondust USA Inc. . + * Copyright © 2006-2017 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,61 +14,44 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "hdhomerun_os.h" +#include "hdhomerun.h" +#if defined(_WINRT) uint32_t random_get32(void) { - HCRYPTPROV hProv; - if (!CryptAcquireContext(&hProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - return (uint32_t)rand(); + return (uint32_t)getcurrenttime(); +} +#else +uint32_t random_get32(void) +{ + static DWORD random_get32_context_tls = 0xFFFFFFFF; + if (random_get32_context_tls == 0xFFFFFFFF) { + random_get32_context_tls = TlsAlloc(); + } + + HCRYPTPROV *phProv = (HCRYPTPROV *)TlsGetValue(random_get32_context_tls); + if (!phProv) { + phProv = (HCRYPTPROV *)calloc(1, sizeof(HCRYPTPROV)); + CryptAcquireContext(phProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + TlsSetValue(random_get32_context_tls, phProv); } uint32_t Result; - CryptGenRandom(hProv, sizeof(Result), (BYTE*)&Result); + if (!CryptGenRandom(*phProv, sizeof(Result), (BYTE *)&Result)) { + return (uint32_t)getcurrenttime(); + } - CryptReleaseContext(hProv, 0); return Result; } +#endif uint64_t getcurrenttime(void) { - static pthread_mutex_t lock = INVALID_HANDLE_VALUE; - static uint64_t result = 0; - static uint32_t previous_time = 0; - - /* Initialization is not thread safe. */ - if (lock == INVALID_HANDLE_VALUE) { - pthread_mutex_init(&lock, NULL); - } - - pthread_mutex_lock(&lock); - - uint32_t current_time = GetTickCount(); - - if (current_time > previous_time) { - result += current_time - previous_time; - } - - previous_time = current_time; - - pthread_mutex_unlock(&lock); - return result; + return GetTickCount64(); } void msleep_approx(uint64_t ms) @@ -90,60 +73,122 @@ void msleep_minimum(uint64_t ms) } } -int pthread_create(pthread_t *tid, void *attr, LPTHREAD_START_ROUTINE start, void *arg) +struct thread_task_execute_args_t { + thread_task_func_t func; + void *arg; +}; + +static DWORD WINAPI thread_task_execute(void *arg) { - *tid = CreateThread(NULL, 0, start, arg, 0, NULL); + struct thread_task_execute_args_t *execute_args = (struct thread_task_execute_args_t *)arg; + execute_args->func(execute_args->arg); + free(execute_args); + return 0; +} + +bool thread_task_create(thread_task_t *tid, thread_task_func_t func, void *arg) +{ + struct thread_task_execute_args_t *execute_args = (struct thread_task_execute_args_t *)malloc(sizeof(struct thread_task_execute_args_t)); + if (!execute_args) { + return false; + } + + execute_args->func = func; + execute_args->arg = arg; + + *tid = CreateThread(NULL, 0, thread_task_execute, execute_args, 0, NULL); if (!*tid) { - return (int)GetLastError(); + free(execute_args); + return false; } - return 0; + + return true; } -int pthread_join(pthread_t tid, void **value_ptr) +void thread_task_join(thread_task_t tid) { while (1) { DWORD ExitCode = 0; if (!GetExitCodeThread(tid, &ExitCode)) { - return (int)GetLastError(); + return; } if (ExitCode != STILL_ACTIVE) { - return 0; + return; } } } -void pthread_mutex_init(pthread_mutex_t *mutex, void *attr) +void thread_mutex_init(thread_mutex_t *mutex) { - *mutex = CreateMutex(NULL, FALSE, NULL); + *mutex = CreateMutex(NULL, false, NULL); } -void pthread_mutex_lock(pthread_mutex_t *mutex) +void thread_mutex_dispose(thread_mutex_t *mutex) +{ + CloseHandle(*mutex); +} + +void thread_mutex_lock(thread_mutex_t *mutex) { WaitForSingleObject(*mutex, INFINITE); } -void pthread_mutex_unlock(pthread_mutex_t *mutex) +void thread_mutex_unlock(thread_mutex_t *mutex) { ReleaseMutex(*mutex); } -/* - * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing. - * Attempting to restore on exit fails to restore if the program is terminated by the user. - * Solution - set the output format each printf. - */ -void console_vprintf(const char *fmt, va_list ap) +void thread_cond_init(thread_cond_t *cond) +{ + *cond = CreateEvent(NULL, false, false, NULL); +} + +void thread_cond_dispose(thread_cond_t *cond) { - UINT cp = GetConsoleOutputCP(); - SetConsoleOutputCP(CP_UTF8); - vprintf(fmt, ap); - SetConsoleOutputCP(cp); + CloseHandle(*cond); } -void console_printf(const char *fmt, ...) +void thread_cond_signal(thread_cond_t *cond) +{ + SetEvent(*cond); +} + +void thread_cond_wait(thread_cond_t *cond) +{ + WaitForSingleObject(*cond, INFINITE); +} + +void thread_cond_wait_with_timeout(thread_cond_t *cond, uint64_t max_wait_time) +{ + WaitForSingleObject(*cond, (DWORD)max_wait_time); +} + +bool hdhomerun_vsprintf(char *buffer, char *end, const char *fmt, va_list ap) +{ + if (buffer >= end) { + return false; + } + + int length = _vsnprintf(buffer, end - buffer - 1, fmt, ap); + if (length < 0) { + *buffer = 0; + return false; + } + + if (buffer + length + 1 > end) { + *(end - 1) = 0; + return false; + + } + + return true; +} + +bool hdhomerun_sprintf(char *buffer, char *end, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - console_vprintf(fmt, ap); + bool result = hdhomerun_vsprintf(buffer, end, fmt, ap); va_end(ap); + return result; } diff --git a/libhdhomerun/hdhomerun_os_windows.h b/libhdhomerun/hdhomerun_os_windows.h index ff9e1d4..932cf9c 100644 --- a/libhdhomerun/hdhomerun_os_windows.h +++ b/libhdhomerun/hdhomerun_os_windows.h @@ -1,12 +1,12 @@ /* * hdhomerun_os_windows.h * - * Copyright © 2006-2010 Silicondust USA Inc. . + * Copyright © 2006-2017 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,88 +14,90 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define _WINSOCKAPI_ -#include +#ifdef _WINRT +#include +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT _WIN32_WINNT_VISTA +#endif +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + #include +#include #include #include #include #include #include +#include +#include #include #include #include #include -#include -#if defined(DLL_IMPORT) -#define LIBTYPE __declspec( dllexport ) -#elif defined(DLL_EXPORT) -#define LIBTYPE __declspec( dllimport ) -#else -#define LIBTYPE +#ifdef LIBHDHOMERUN_DLLEXPORT +#define LIBHDHOMERUN_API __declspec(dllexport) +#endif +#ifdef LIBHDHOMERUN_DLLIMPORT +#define LIBHDHOMERUN_API __declspec(dllimport) +#endif +#ifndef LIBHDHOMERUN_API +#define LIBHDHOMERUN_API #endif -typedef int bool_t; -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef signed __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; typedef void (*sig_t)(int); -typedef HANDLE pthread_t; -typedef HANDLE pthread_mutex_t; +typedef void (*thread_task_func_t)(void *arg); +typedef HANDLE thread_task_t; +typedef HANDLE thread_mutex_t; +typedef HANDLE thread_cond_t; +#if !defined(va_copy) #define va_copy(x, y) x = y +#endif + #define atoll _atoi64 #define strdup _strdup #define strcasecmp _stricmp -#define snprintf _snprintf +#define strncasecmp _strnicmp #define fseeko _fseeki64 #define ftello _ftelli64 -#define THREAD_FUNC_PREFIX DWORD WINAPI #ifdef __cplusplus extern "C" { #endif -extern LIBTYPE uint32_t random_get32(void); -extern LIBTYPE uint64_t getcurrenttime(void); -extern LIBTYPE void msleep_approx(uint64_t ms); -extern LIBTYPE void msleep_minimum(uint64_t ms); +extern LIBHDHOMERUN_API uint32_t random_get32(void); +extern LIBHDHOMERUN_API uint64_t getcurrenttime(void); +extern LIBHDHOMERUN_API void msleep_approx(uint64_t ms); +extern LIBHDHOMERUN_API void msleep_minimum(uint64_t ms); -extern LIBTYPE int pthread_create(pthread_t *tid, void *attr, LPTHREAD_START_ROUTINE start, void *arg); -extern LIBTYPE int pthread_join(pthread_t tid, void **value_ptr); -extern LIBTYPE void pthread_mutex_init(pthread_mutex_t *mutex, void *attr); -extern LIBTYPE void pthread_mutex_lock(pthread_mutex_t *mutex); -extern LIBTYPE void pthread_mutex_unlock(pthread_mutex_t *mutex); +extern LIBHDHOMERUN_API bool thread_task_create(thread_task_t *tid, thread_task_func_t func, void *arg); +extern LIBHDHOMERUN_API void thread_task_join(thread_task_t tid); -/* - * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing. - * Attempting to restore on exit fails to restore if the program is terminated by the user. - * Solution - set the output format each printf. - */ -extern LIBTYPE void console_vprintf(const char *fmt, va_list ap); -extern LIBTYPE void console_printf(const char *fmt, ...); +extern LIBHDHOMERUN_API void thread_mutex_init(thread_mutex_t *mutex); +extern LIBHDHOMERUN_API void thread_mutex_dispose(thread_mutex_t *mutex); +extern LIBHDHOMERUN_API void thread_mutex_lock(thread_mutex_t *mutex); +extern LIBHDHOMERUN_API void thread_mutex_unlock(thread_mutex_t *mutex); + +extern LIBHDHOMERUN_API void thread_cond_init(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_dispose(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_signal(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_wait(thread_cond_t *cond); +extern LIBHDHOMERUN_API void thread_cond_wait_with_timeout(thread_cond_t *cond, uint64_t max_wait_time); + +extern LIBHDHOMERUN_API bool hdhomerun_vsprintf(char *buffer, char *end, const char *fmt, va_list ap); +extern LIBHDHOMERUN_API bool hdhomerun_sprintf(char *buffer, char *end, const char *fmt, ...); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_pkt.c b/libhdhomerun/hdhomerun_pkt.c index bc34ba2..d8071c6 100644 --- a/libhdhomerun/hdhomerun_pkt.c +++ b/libhdhomerun/hdhomerun_pkt.c @@ -1,12 +1,12 @@ /* * hdhomerun_pkt.c * - * Copyright © 2005-2006 Silicondust USA Inc. . + * Copyright © 2006-2014 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" @@ -137,6 +125,12 @@ uint8_t *hdhomerun_pkt_read_tlv(struct hdhomerun_pkt_t *pkt, uint8_t *ptag, size return pkt->pos + *plength; } +void hdhomerun_pkt_read_mem(struct hdhomerun_pkt_t *pkt, void *mem, size_t length) +{ + memcpy(mem, pkt->pos, length); + pkt->pos += length; +} + void hdhomerun_pkt_write_u8(struct hdhomerun_pkt_t *pkt, uint8_t v) { *pkt->pos++ = v; diff --git a/libhdhomerun/hdhomerun_pkt.h b/libhdhomerun/hdhomerun_pkt.h index 9ddf6fd..9821b91 100644 --- a/libhdhomerun/hdhomerun_pkt.h +++ b/libhdhomerun/hdhomerun_pkt.h @@ -1,12 +1,12 @@ /* * hdhomerun_pkt.h * - * Copyright © 2005-2006 Silicondust USA Inc. . + * Copyright © 2006-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus extern "C" { @@ -138,9 +126,14 @@ extern "C" { #define HDHOMERUN_TAG_GETSET_VALUE 0x04 #define HDHOMERUN_TAG_GETSET_LOCKKEY 0x15 #define HDHOMERUN_TAG_ERROR_MESSAGE 0x05 +#define HDHOMERUN_TAG_TUNER_COUNT 0x10 +#define HDHOMERUN_TAG_DEVICE_AUTH_BIN 0x29 +#define HDHOMERUN_TAG_BASE_URL 0x2A +#define HDHOMERUN_TAG_DEVICE_AUTH_STR 0x2B #define HDHOMERUN_DEVICE_TYPE_WILDCARD 0xFFFFFFFF #define HDHOMERUN_DEVICE_TYPE_TUNER 0x00000001 +#define HDHOMERUN_DEVICE_TYPE_STORAGE 0x00000005 #define HDHOMERUN_DEVICE_ID_WILDCARD 0xFFFFFFFF #define HDHOMERUN_MIN_PEEK_LENGTH 4 @@ -153,24 +146,25 @@ struct hdhomerun_pkt_t { uint8_t buffer[3074]; }; -extern LIBTYPE struct hdhomerun_pkt_t *hdhomerun_pkt_create(void); -extern LIBTYPE void hdhomerun_pkt_destroy(struct hdhomerun_pkt_t *pkt); -extern LIBTYPE void hdhomerun_pkt_reset(struct hdhomerun_pkt_t *pkt); +extern LIBHDHOMERUN_API struct hdhomerun_pkt_t *hdhomerun_pkt_create(void); +extern LIBHDHOMERUN_API void hdhomerun_pkt_destroy(struct hdhomerun_pkt_t *pkt); +extern LIBHDHOMERUN_API void hdhomerun_pkt_reset(struct hdhomerun_pkt_t *pkt); -extern LIBTYPE uint8_t hdhomerun_pkt_read_u8(struct hdhomerun_pkt_t *pkt); -extern LIBTYPE uint16_t hdhomerun_pkt_read_u16(struct hdhomerun_pkt_t *pkt); -extern LIBTYPE uint32_t hdhomerun_pkt_read_u32(struct hdhomerun_pkt_t *pkt); -extern LIBTYPE size_t hdhomerun_pkt_read_var_length(struct hdhomerun_pkt_t *pkt); -extern LIBTYPE uint8_t *hdhomerun_pkt_read_tlv(struct hdhomerun_pkt_t *pkt, uint8_t *ptag, size_t *plength); +extern LIBHDHOMERUN_API uint8_t hdhomerun_pkt_read_u8(struct hdhomerun_pkt_t *pkt); +extern LIBHDHOMERUN_API uint16_t hdhomerun_pkt_read_u16(struct hdhomerun_pkt_t *pkt); +extern LIBHDHOMERUN_API uint32_t hdhomerun_pkt_read_u32(struct hdhomerun_pkt_t *pkt); +extern LIBHDHOMERUN_API size_t hdhomerun_pkt_read_var_length(struct hdhomerun_pkt_t *pkt); +extern LIBHDHOMERUN_API uint8_t *hdhomerun_pkt_read_tlv(struct hdhomerun_pkt_t *pkt, uint8_t *ptag, size_t *plength); +extern LIBHDHOMERUN_API void hdhomerun_pkt_read_mem(struct hdhomerun_pkt_t *pkt, void *mem, size_t length); -extern LIBTYPE void hdhomerun_pkt_write_u8(struct hdhomerun_pkt_t *pkt, uint8_t v); -extern LIBTYPE void hdhomerun_pkt_write_u16(struct hdhomerun_pkt_t *pkt, uint16_t v); -extern LIBTYPE void hdhomerun_pkt_write_u32(struct hdhomerun_pkt_t *pkt, uint32_t v); -extern LIBTYPE void hdhomerun_pkt_write_var_length(struct hdhomerun_pkt_t *pkt, size_t v); -extern LIBTYPE void hdhomerun_pkt_write_mem(struct hdhomerun_pkt_t *pkt, const void *mem, size_t length); +extern LIBHDHOMERUN_API void hdhomerun_pkt_write_u8(struct hdhomerun_pkt_t *pkt, uint8_t v); +extern LIBHDHOMERUN_API void hdhomerun_pkt_write_u16(struct hdhomerun_pkt_t *pkt, uint16_t v); +extern LIBHDHOMERUN_API void hdhomerun_pkt_write_u32(struct hdhomerun_pkt_t *pkt, uint32_t v); +extern LIBHDHOMERUN_API void hdhomerun_pkt_write_var_length(struct hdhomerun_pkt_t *pkt, size_t v); +extern LIBHDHOMERUN_API void hdhomerun_pkt_write_mem(struct hdhomerun_pkt_t *pkt, const void *mem, size_t length); -extern LIBTYPE bool_t hdhomerun_pkt_open_frame(struct hdhomerun_pkt_t *pkt, uint16_t *ptype); -extern LIBTYPE void hdhomerun_pkt_seal_frame(struct hdhomerun_pkt_t *pkt, uint16_t frame_type); +extern LIBHDHOMERUN_API int hdhomerun_pkt_open_frame(struct hdhomerun_pkt_t *pkt, uint16_t *ptype); +extern LIBHDHOMERUN_API void hdhomerun_pkt_seal_frame(struct hdhomerun_pkt_t *pkt, uint16_t frame_type); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_sock.h b/libhdhomerun/hdhomerun_sock.h index 60e0b15..5710a5f 100644 --- a/libhdhomerun/hdhomerun_sock.h +++ b/libhdhomerun/hdhomerun_sock.h @@ -1,12 +1,12 @@ /* * hdhomerun_sock.h * - * Copyright © 2010 Silicondust USA Inc. . + * Copyright © 2010-2016 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,48 +14,49 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus extern "C" { #endif -#define HDHOMERUN_SOCK_INVALID -1 +struct hdhomerun_local_ip_info_t { + uint32_t ip_addr; + uint32_t subnet_mask; +}; -typedef int hdhomerun_sock_t; +extern LIBHDHOMERUN_API int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count); +extern LIBHDHOMERUN_API void hdhomerun_local_ip_info_set_str(const char *ip_info_str); /* WinRT only */ -extern LIBTYPE hdhomerun_sock_t hdhomerun_sock_create_udp(void); -extern LIBTYPE hdhomerun_sock_t hdhomerun_sock_create_tcp(void); -extern LIBTYPE void hdhomerun_sock_destroy(hdhomerun_sock_t sock); +struct hdhomerun_sock_t; -extern LIBTYPE int hdhomerun_sock_getlasterror(void); -extern LIBTYPE uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock); -extern LIBTYPE uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock); -extern LIBTYPE uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock); -extern LIBTYPE uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name); +extern LIBHDHOMERUN_API struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void); +extern LIBHDHOMERUN_API struct hdhomerun_sock_t *hdhomerun_sock_create_tcp(void); +extern LIBHDHOMERUN_API void hdhomerun_sock_stop(struct hdhomerun_sock_t *sock); +extern LIBHDHOMERUN_API void hdhomerun_sock_destroy(struct hdhomerun_sock_t *sock); -extern LIBTYPE bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port); -extern LIBTYPE bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout); +extern LIBHDHOMERUN_API void hdhomerun_sock_set_send_buffer_size(struct hdhomerun_sock_t *sock, size_t size); +extern LIBHDHOMERUN_API void hdhomerun_sock_set_recv_buffer_size(struct hdhomerun_sock_t *sock, size_t size); +extern LIBHDHOMERUN_API void hdhomerun_sock_set_allow_reuse(struct hdhomerun_sock_t *sock); -extern LIBTYPE bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout); -extern LIBTYPE bool_t hdhomerun_sock_sendto(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout); +extern LIBHDHOMERUN_API int hdhomerun_sock_getlasterror(void); +extern LIBHDHOMERUN_API uint32_t hdhomerun_sock_getsockname_addr(struct hdhomerun_sock_t *sock); +extern LIBHDHOMERUN_API uint16_t hdhomerun_sock_getsockname_port(struct hdhomerun_sock_t *sock); +extern LIBHDHOMERUN_API uint32_t hdhomerun_sock_getpeername_addr(struct hdhomerun_sock_t *sock); +extern LIBHDHOMERUN_API uint32_t hdhomerun_sock_getaddrinfo_addr(struct hdhomerun_sock_t *sock, const char *name); -extern LIBTYPE bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout); -extern LIBTYPE bool_t hdhomerun_sock_recvfrom(hdhomerun_sock_t sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout); +extern LIBHDHOMERUN_API bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip); +extern LIBHDHOMERUN_API bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip); +extern LIBHDHOMERUN_API bool hdhomerun_sock_bind(struct hdhomerun_sock_t *sock, uint32_t local_addr, uint16_t local_port, bool allow_reuse); +extern LIBHDHOMERUN_API bool hdhomerun_sock_connect(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout); + +extern LIBHDHOMERUN_API bool hdhomerun_sock_send(struct hdhomerun_sock_t *sock, const void *data, size_t length, uint64_t timeout); +extern LIBHDHOMERUN_API bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout); + +extern LIBHDHOMERUN_API bool hdhomerun_sock_recv(struct hdhomerun_sock_t *sock, void *data, size_t *length, uint64_t timeout); +extern LIBHDHOMERUN_API bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout); #ifdef __cplusplus } diff --git a/libhdhomerun/hdhomerun_sock_posix.c b/libhdhomerun/hdhomerun_sock_posix.c new file mode 100644 index 0000000..d71acf0 --- /dev/null +++ b/libhdhomerun/hdhomerun_sock_posix.c @@ -0,0 +1,544 @@ +/* + * hdhomerun_sock_posix.c + * + * Copyright © 2010-2016 Silicondust USA Inc. . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hdhomerun.h" + +#include +#include + +#ifndef SIOCGIFCONF +#include +#endif + +#ifndef _SIZEOF_ADDR_IFREQ +#define _SIZEOF_ADDR_IFREQ(x) sizeof(x) +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +struct hdhomerun_sock_t { + int sock; +}; + +int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count) +{ + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + return -1; + } + + struct ifconf ifc; + size_t ifreq_buffer_size = 1024; + + while (1) { + ifc.ifc_len = (int)ifreq_buffer_size; + ifc.ifc_buf = (char *)malloc(ifreq_buffer_size); + if (!ifc.ifc_buf) { + close(sock); + return -1; + } + + memset(ifc.ifc_buf, 0, ifreq_buffer_size); + + if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) { + free(ifc.ifc_buf); + close(sock); + return -1; + } + + if (ifc.ifc_len < (int)ifreq_buffer_size) { + break; + } + + free(ifc.ifc_buf); + ifreq_buffer_size += 1024; + } + + char *ptr = ifc.ifc_buf; + char *end = ifc.ifc_buf + ifc.ifc_len; + + int count = 0; + while (ptr < end) { + struct ifreq *ifr = (struct ifreq *)ptr; + ptr += _SIZEOF_ADDR_IFREQ(*ifr); + + /* Flags. */ + if (ioctl(sock, SIOCGIFFLAGS, ifr) != 0) { + continue; + } + + if ((ifr->ifr_flags & IFF_UP) == 0) { + continue; + } + if ((ifr->ifr_flags & IFF_RUNNING) == 0) { + continue; + } + + /* Local IP address. */ + if (ioctl(sock, SIOCGIFADDR, ifr) != 0) { + continue; + } + + struct sockaddr_in *ip_addr_in = (struct sockaddr_in *)&(ifr->ifr_addr); + uint32_t ip_addr = ntohl(ip_addr_in->sin_addr.s_addr); + if (ip_addr == 0) { + continue; + } + + /* Subnet mask. */ + if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) { + continue; + } + + struct sockaddr_in *subnet_mask_in = (struct sockaddr_in *)&(ifr->ifr_addr); + uint32_t subnet_mask = ntohl(subnet_mask_in->sin_addr.s_addr); + + /* Report. */ + if (count < max_count) { + struct hdhomerun_local_ip_info_t *ip_info = &ip_info_list[count]; + ip_info->ip_addr = ip_addr; + ip_info->subnet_mask = subnet_mask; + } + + count++; + } + + free(ifc.ifc_buf); + close(sock); + return count; +} + +static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol) +{ + struct hdhomerun_sock_t *sock = (struct hdhomerun_sock_t *)calloc(1, sizeof(struct hdhomerun_sock_t)); + if (!sock) { + return NULL; + } + + /* Create socket. */ + sock->sock = socket(AF_INET, protocol, 0); + if (sock->sock == -1) { + free(sock); + return NULL; + } + + /* Set non-blocking */ + if (fcntl(sock->sock, F_SETFL, O_NONBLOCK) != 0) { + hdhomerun_sock_destroy(sock); + return NULL; + } + + /* Configure socket not to generate pipe-error signal (BSD/OSX). */ +#if defined(SO_NOSIGPIPE) + int set = 1; + setsockopt(sock->sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&set, sizeof(set)); +#endif + + /* Success. */ + return sock; +} + +struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void) +{ + struct hdhomerun_sock_t *sock = hdhomerun_sock_create_internal(SOCK_DGRAM); + if (!sock) { + return NULL; + } + + /* Allow broadcast. */ + int sock_opt = 1; + setsockopt(sock->sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt)); + + /* Success. */ + return sock; +} + +struct hdhomerun_sock_t *hdhomerun_sock_create_tcp(void) +{ + return hdhomerun_sock_create_internal(SOCK_STREAM); +} + +void hdhomerun_sock_destroy(struct hdhomerun_sock_t *sock) +{ + close(sock->sock); + free(sock); +} + +void hdhomerun_sock_stop(struct hdhomerun_sock_t *sock) +{ + shutdown(sock->sock, SHUT_RDWR); +} + +void hdhomerun_sock_set_send_buffer_size(struct hdhomerun_sock_t *sock, size_t size) +{ + int size_opt = (int)size; + setsockopt(sock->sock, SOL_SOCKET, SO_SNDBUF, (char *)&size_opt, sizeof(size_opt)); +} + +void hdhomerun_sock_set_recv_buffer_size(struct hdhomerun_sock_t *sock, size_t size) +{ + int size_opt = (int)size; + setsockopt(sock->sock, SOL_SOCKET, SO_RCVBUF, (char *)&size_opt, sizeof(size_opt)); +} + +void hdhomerun_sock_set_allow_reuse(struct hdhomerun_sock_t *sock) +{ + int sock_opt = 1; + setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt)); +} + +int hdhomerun_sock_getlasterror(void) +{ + return errno; +} + +uint32_t hdhomerun_sock_getsockname_addr(struct hdhomerun_sock_t *sock) +{ + struct sockaddr_in sock_addr; + socklen_t sockaddr_size = sizeof(sock_addr); + + if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { + return 0; + } + + return ntohl(sock_addr.sin_addr.s_addr); +} + +uint16_t hdhomerun_sock_getsockname_port(struct hdhomerun_sock_t *sock) +{ + struct sockaddr_in sock_addr; + socklen_t sockaddr_size = sizeof(sock_addr); + + if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { + return 0; + } + + return ntohs(sock_addr.sin_port); +} + +uint32_t hdhomerun_sock_getpeername_addr(struct hdhomerun_sock_t *sock) +{ + struct sockaddr_in sock_addr; + socklen_t sockaddr_size = sizeof(sock_addr); + + if (getpeername(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { + return 0; + } + + return ntohl(sock_addr.sin_addr.s_addr); +} + +uint32_t hdhomerun_sock_getaddrinfo_addr(struct hdhomerun_sock_t *sock, const char *name) +{ + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + struct addrinfo *sock_info; + if (getaddrinfo(name, NULL, &hints, &sock_info) != 0) { + return 0; + } + + struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr; + uint32_t addr = ntohl(sock_addr->sin_addr.s_addr); + + freeaddrinfo(sock_info); + return addr; +} + +bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip) +{ + struct ip_mreq imr; + memset(&imr, 0, sizeof(imr)); + imr.imr_multiaddr.s_addr = htonl(multicast_ip); + imr.imr_interface.s_addr = htonl(local_ip); + + if (setsockopt(sock->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { + return false; + } + + return true; +} + +bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip) +{ + struct ip_mreq imr; + memset(&imr, 0, sizeof(imr)); + imr.imr_multiaddr.s_addr = htonl(multicast_ip); + imr.imr_interface.s_addr = htonl(local_ip); + + if (setsockopt(sock->sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { + return false; + } + + return true; +} + +bool hdhomerun_sock_bind(struct hdhomerun_sock_t *sock, uint32_t local_addr, uint16_t local_port, bool allow_reuse) +{ + int sock_opt = allow_reuse; + setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt)); + + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = htonl(local_addr); + sock_addr.sin_port = htons(local_port); + + if (bind(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { + return false; + } + + return true; +} + +bool hdhomerun_sock_connect(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout) +{ + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = htonl(remote_addr); + sock_addr.sin_port = htons(remote_port); + + if (connect(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { + if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + return false; + } + } + + struct pollfd poll_event; + poll_event.fd = sock->sock; + poll_event.events = POLLOUT; + poll_event.revents = 0; + + if (poll(&poll_event, 1, (int)timeout) <= 0) { + return false; + } + + if ((poll_event.revents & POLLOUT) == 0) { + return false; + } + + return true; +} + +bool hdhomerun_sock_send(struct hdhomerun_sock_t *sock, const void *data, size_t length, uint64_t timeout) +{ + const uint8_t *ptr = (const uint8_t *)data; + ssize_t ret = send(sock->sock, ptr, length, MSG_NOSIGNAL); + if (ret >= (ssize_t)length) { + return true; + } + + if ((ret < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + return false; + } + + if (ret > 0) { + ptr += ret; + length -= ret; + } + + uint64_t stop_time = getcurrenttime() + timeout; + + while (1) { + struct pollfd poll_event; + poll_event.fd = sock->sock; + poll_event.events = POLLOUT; + poll_event.revents = 0; + + if (poll(&poll_event, 1, (int)timeout) <= 0) { + return false; + } + + if ((poll_event.revents & POLLOUT) == 0) { + return false; + } + + ret = send(sock->sock, ptr, length, MSG_NOSIGNAL); + if (ret >= (ssize_t)length) { + return true; + } + + if ((ret < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + return false; + } + + if (ret > 0) { + ptr += ret; + length -= ret; + } + + uint64_t current_time = getcurrenttime(); + if (current_time >= stop_time) { + return false; + } + + timeout = stop_time - current_time; + } +} + +bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout) +{ + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = htonl(remote_addr); + sock_addr.sin_port = htons(remote_port); + + const uint8_t *ptr = (const uint8_t *)data; + ssize_t ret = sendto(sock->sock, ptr, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); + if (ret >= (ssize_t)length) { + return true; + } + + if ((ret < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + return false; + } + + if (ret > 0) { + ptr += ret; + length -= ret; + } + + uint64_t stop_time = getcurrenttime() + timeout; + + while (1) { + struct pollfd poll_event; + poll_event.fd = sock->sock; + poll_event.events = POLLOUT; + poll_event.revents = 0; + + if (poll(&poll_event, 1, (int)timeout) <= 0) { + return false; + } + + if ((poll_event.revents & POLLOUT) == 0) { + return false; + } + + ret = sendto(sock->sock, ptr, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); + if (ret >= (ssize_t)length) { + return true; + } + + if ((ret < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + return false; + } + + if (ret > 0) { + ptr += ret; + length -= ret; + } + + uint64_t current_time = getcurrenttime(); + if (current_time >= stop_time) { + return false; + } + + timeout = stop_time - current_time; + } +} + +bool hdhomerun_sock_recv(struct hdhomerun_sock_t *sock, void *data, size_t *length, uint64_t timeout) +{ + ssize_t ret = recv(sock->sock, data, *length, 0); + if (ret > 0) { + *length = (size_t)ret; + return true; + } + + if (ret == 0) { + return false; + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + return false; + } + + struct pollfd poll_event; + poll_event.fd = sock->sock; + poll_event.events = POLLIN; + poll_event.revents = 0; + + if (poll(&poll_event, 1, (int)timeout) <= 0) { + return false; + } + + if ((poll_event.revents & POLLIN) == 0) { + return false; + } + + ret = recv(sock->sock, data, *length, 0); + if (ret > 0) { + *length = (size_t)ret; + return true; + } + + return false; +} + +bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout) +{ + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); + socklen_t sockaddr_size = sizeof(sock_addr); + + ssize_t ret = recvfrom(sock->sock, data, *length, 0, (struct sockaddr *)&sock_addr, &sockaddr_size); + if (ret > 0) { + *remote_addr = ntohl(sock_addr.sin_addr.s_addr); + *remote_port = ntohs(sock_addr.sin_port); + *length = (size_t)ret; + return true; + } + + if (ret == 0) { + return false; + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + return false; + } + + struct pollfd poll_event; + poll_event.fd = sock->sock; + poll_event.events = POLLIN; + poll_event.revents = 0; + + if (poll(&poll_event, 1, (int)timeout) <= 0) { + return false; + } + + if ((poll_event.revents & POLLIN) == 0) { + return false; + } + + ret = recvfrom(sock->sock, data, *length, 0, (struct sockaddr *)&sock_addr, &sockaddr_size); + if (ret > 0) { + *remote_addr = ntohl(sock_addr.sin_addr.s_addr); + *remote_port = ntohs(sock_addr.sin_port); + *length = (size_t)ret; + return true; + } + + return false; +} diff --git a/libhdhomerun/hdhomerun_sock_windows.c b/libhdhomerun/hdhomerun_sock_windows.c index 994ac54..ea5d232 100644 --- a/libhdhomerun/hdhomerun_sock_windows.c +++ b/libhdhomerun/hdhomerun_sock_windows.c @@ -1,12 +1,12 @@ /* * hdhomerun_sock_windows.c * - * Copyright © 2010 Silicondust USA Inc. . + * Copyright © 2010-2016 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,84 +14,218 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "hdhomerun.h" +#include + +struct hdhomerun_sock_t { + SOCKET sock; + HANDLE event; + long events_selected; +}; + +#if defined(_WINRT) +static char *hdhomerun_local_ip_info_str = NULL; + /* - * Implementation notes: - * - * API specifies timeout for each operation (or zero for non-blocking). - * - * It is not possible to rely on the OS socket timeout as this will fail to - * detect the command-response situation where data is sent successfully and - * the other end chooses not to send a response (other than the TCP ack). - * - * Windows supports select() however native WSA events are used to: - * - avoid problems with socket numbers above 1024. - * - wait without allowing other events handlers to run (important for use - * with win7 WMC). + * String format: ip address '/' subnet mask bits ... + * Example: "192.168.0.100/24 169.254.0.100/16" */ +void hdhomerun_local_ip_info_set_str(const char *ip_info_str) +{ + if (hdhomerun_local_ip_info_str) { + free(hdhomerun_local_ip_info_str); + } -#include "hdhomerun.h" + hdhomerun_local_ip_info_str = strdup(ip_info_str); +} + +int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count) +{ + const char *ptr = hdhomerun_local_ip_info_str; + if (!ptr) { + return 0; + } + + struct hdhomerun_local_ip_info_t *ip_info = ip_info_list; + int count = 0; + + while (count < max_count) { + unsigned int a[4]; + unsigned int mask_bitcount; + if (sscanf(ptr, "%u.%u.%u.%u/%u", &a[0], &a[1], &a[2], &a[3], &mask_bitcount) != 5) { + break; + } + + ip_info->ip_addr = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0)); + ip_info->subnet_mask = 0xFFFFFFFF << (32 - mask_bitcount); + ip_info++; + + count++; + + ptr = strchr(ptr, ' '); + if (!ptr) { + break; + } + + ptr++; + } + + return count; +} +#endif + +#if !defined(_WINRT) +int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count) +{ + PIP_ADAPTER_INFO AdapterInfo; + ULONG AdapterInfoLength = sizeof(IP_ADAPTER_INFO) * 16; + + while (1) { + AdapterInfo = (IP_ADAPTER_INFO *)malloc(AdapterInfoLength); + if (!AdapterInfo) { + return -1; + } + + ULONG LengthNeeded = AdapterInfoLength; + DWORD Ret = GetAdaptersInfo(AdapterInfo, &LengthNeeded); + if (Ret == NO_ERROR) { + break; + } + + free(AdapterInfo); + + if (Ret != ERROR_BUFFER_OVERFLOW) { + return -1; + } + if (AdapterInfoLength >= LengthNeeded) { + return -1; + } + + AdapterInfoLength = LengthNeeded; + } + + int count = 0; + PIP_ADAPTER_INFO Adapter = AdapterInfo; + while (Adapter) { + IP_ADDR_STRING *IPAddr = &Adapter->IpAddressList; + while (IPAddr) { + uint32_t ip_addr = ntohl(inet_addr(IPAddr->IpAddress.String)); + uint32_t subnet_mask = ntohl(inet_addr(IPAddr->IpMask.String)); + + if (ip_addr == 0) { + IPAddr = IPAddr->Next; + continue; + } + + if (count < max_count) { + struct hdhomerun_local_ip_info_t *ip_info = &ip_info_list[count]; + ip_info->ip_addr = ip_addr; + ip_info->subnet_mask = subnet_mask; + } + + count++; + IPAddr = IPAddr->Next; + } -hdhomerun_sock_t hdhomerun_sock_create_udp(void) + if (count >= max_count) { + break; + } + + Adapter = Adapter->Next; + } + + free(AdapterInfo); + return count; +} +#endif + +static struct hdhomerun_sock_t *hdhomerun_sock_create_internal(int protocol) { + struct hdhomerun_sock_t *sock = (struct hdhomerun_sock_t *)calloc(1, sizeof(struct hdhomerun_sock_t)); + if (!sock) { + return NULL; + } + /* Create socket. */ - hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_DGRAM, 0); - if (sock == -1) { - return HDHOMERUN_SOCK_INVALID; + sock->sock = socket(AF_INET, protocol, 0); + if (sock->sock == INVALID_SOCKET) { + free(sock); + return NULL; } /* Set non-blocking */ unsigned long mode = 1; - if (ioctlsocket(sock, FIONBIO, &mode) != 0) { - closesocket(sock); - return HDHOMERUN_SOCK_INVALID; + if (ioctlsocket(sock->sock, FIONBIO, &mode) != 0) { + hdhomerun_sock_destroy(sock); + return NULL; } - /* Allow broadcast. */ - int sock_opt = 1; - setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt)); + /* Event */ + sock->event = CreateEvent(NULL, false, false, NULL); + if (!sock->event) { + hdhomerun_sock_destroy(sock); + return NULL; + } /* Success. */ return sock; } -hdhomerun_sock_t hdhomerun_sock_create_tcp(void) +struct hdhomerun_sock_t *hdhomerun_sock_create_udp(void) { - /* Create socket. */ - hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_STREAM, 0); - if (sock == -1) { - return HDHOMERUN_SOCK_INVALID; + struct hdhomerun_sock_t *sock = hdhomerun_sock_create_internal(SOCK_DGRAM); + if (!sock) { + return NULL; } - /* Set non-blocking */ - unsigned long mode = 1; - if (ioctlsocket(sock, FIONBIO, &mode) != 0) { - closesocket(sock); - return HDHOMERUN_SOCK_INVALID; - } + /* Allow broadcast. */ + int sock_opt = 1; + setsockopt(sock->sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt)); /* Success. */ return sock; } -void hdhomerun_sock_destroy(hdhomerun_sock_t sock) +struct hdhomerun_sock_t *hdhomerun_sock_create_tcp(void) { - closesocket(sock); + return hdhomerun_sock_create_internal(SOCK_STREAM); +} + +void hdhomerun_sock_destroy(struct hdhomerun_sock_t *sock) +{ + if (sock->event) { + CloseHandle(sock->event); + } + + closesocket(sock->sock); + free(sock); +} + +void hdhomerun_sock_stop(struct hdhomerun_sock_t *sock) +{ + shutdown(sock->sock, SD_BOTH); +} + +void hdhomerun_sock_set_send_buffer_size(struct hdhomerun_sock_t *sock, size_t size) +{ + int size_opt = (int)size; + setsockopt(sock->sock, SOL_SOCKET, SO_SNDBUF, (char *)&size_opt, sizeof(size_opt)); +} + +void hdhomerun_sock_set_recv_buffer_size(struct hdhomerun_sock_t *sock, size_t size) +{ + int size_opt = (int)size; + setsockopt(sock->sock, SOL_SOCKET, SO_RCVBUF, (char *)&size_opt, sizeof(size_opt)); +} + +void hdhomerun_sock_set_allow_reuse(struct hdhomerun_sock_t *sock) +{ + int sock_opt = 1; + setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt)); } int hdhomerun_sock_getlasterror(void) @@ -99,43 +233,43 @@ int hdhomerun_sock_getlasterror(void) return WSAGetLastError(); } -uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock) +uint32_t hdhomerun_sock_getsockname_addr(struct hdhomerun_sock_t *sock) { struct sockaddr_in sock_addr; int sockaddr_size = sizeof(sock_addr); - if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { + if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { return 0; } return ntohl(sock_addr.sin_addr.s_addr); } -uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock) +uint16_t hdhomerun_sock_getsockname_port(struct hdhomerun_sock_t *sock) { struct sockaddr_in sock_addr; int sockaddr_size = sizeof(sock_addr); - if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { + if (getsockname(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { return 0; } return ntohs(sock_addr.sin_port); } -uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock) +uint32_t hdhomerun_sock_getpeername_addr(struct hdhomerun_sock_t *sock) { struct sockaddr_in sock_addr; int sockaddr_size = sizeof(sock_addr); - if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { + if (getpeername(sock->sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { return 0; } return ntohl(sock_addr.sin_addr.s_addr); } -uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name) +uint32_t hdhomerun_sock_getaddrinfo_addr(struct hdhomerun_sock_t *sock, const char *name) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); @@ -144,7 +278,7 @@ uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name hints.ai_protocol = IPPROTO_TCP; struct addrinfo *sock_info; - if (getaddrinfo(name, "", &hints, &sock_info) != 0) { + if (getaddrinfo(name, NULL, &hints, &sock_info) != 0) { return 0; } @@ -155,100 +289,119 @@ uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name return addr; } -bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port) +bool hdhomerun_sock_join_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip) +{ + struct ip_mreq imr; + memset(&imr, 0, sizeof(imr)); + imr.imr_multiaddr.s_addr = htonl(multicast_ip); + imr.imr_interface.s_addr = htonl(local_ip); + + if (setsockopt(sock->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { + return false; + } + + return true; +} + +bool hdhomerun_sock_leave_multicast_group(struct hdhomerun_sock_t *sock, uint32_t multicast_ip, uint32_t local_ip) { + struct ip_mreq imr; + memset(&imr, 0, sizeof(imr)); + imr.imr_multiaddr.s_addr = htonl(multicast_ip); + imr.imr_interface.s_addr = htonl(local_ip); + + if (setsockopt(sock->sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { + return false; + } + + return true; +} + +bool hdhomerun_sock_bind(struct hdhomerun_sock_t *sock, uint32_t local_addr, uint16_t local_port, bool allow_reuse) +{ + int sock_opt = allow_reuse; + setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt)); + struct sockaddr_in sock_addr; memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = htonl(local_addr); sock_addr.sin_port = htons(local_port); - if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { - return FALSE; + if (bind(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { + return false; } - return TRUE; + return true; } -bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout) +static bool hdhomerun_sock_event_select(struct hdhomerun_sock_t *sock, long events) { - WSAEVENT wsa_event = WSACreateEvent(); - if (wsa_event == WSA_INVALID_EVENT) { - return FALSE; + if (sock->events_selected != events) { + if (WSAEventSelect(sock->sock, sock->event, events) == SOCKET_ERROR) { + return false; + } + sock->events_selected = events; } - if (WSAEventSelect(sock, wsa_event, FD_CONNECT) == SOCKET_ERROR) { - WSACloseEvent(wsa_event); - return FALSE; + ResetEvent(sock->event); + return true; +} + +bool hdhomerun_sock_connect(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout) +{ + if (!hdhomerun_sock_event_select(sock, FD_WRITE | FD_CLOSE)) { + return false; } - /* Connect (non-blocking). */ struct sockaddr_in sock_addr; memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = htonl(remote_addr); sock_addr.sin_port = htons(remote_port); - if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { + if (connect(sock->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { if (WSAGetLastError() != WSAEWOULDBLOCK) { - WSACloseEvent(wsa_event); - return FALSE; + return false; } } - /* Wait for connect to complete (both success and failure will signal). */ - DWORD ret = WaitForSingleObjectEx(wsa_event, (DWORD)timeout, FALSE); - WSACloseEvent(wsa_event); - - if (ret != WAIT_OBJECT_0) { - return FALSE; + DWORD wait_ret = WaitForSingleObjectEx(sock->event, (DWORD)timeout, false); + if (wait_ret != WAIT_OBJECT_0) { + return false; } - /* Detect success/failure. */ - int sockaddr_size = sizeof(sock_addr); - if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { - return FALSE; - } - - return TRUE; -} - -static bool_t hdhomerun_sock_wait_for_event(hdhomerun_sock_t sock, long event_type, uint64_t stop_time) -{ - uint64_t current_time = getcurrenttime(); - if (current_time >= stop_time) { - return FALSE; + WSANETWORKEVENTS network_events; + if (WSAEnumNetworkEvents(sock->sock, sock->event, &network_events) == SOCKET_ERROR) { + return false; } - - WSAEVENT wsa_event = WSACreateEvent(); - if (wsa_event == WSA_INVALID_EVENT) { - return FALSE; + if ((network_events.lNetworkEvents & FD_WRITE) == 0) { + return false; } - - if (WSAEventSelect(sock, wsa_event, event_type) == SOCKET_ERROR) { - WSACloseEvent(wsa_event); - return FALSE; + if (network_events.lNetworkEvents & FD_CLOSE) { + return false; } - DWORD ret = WaitForSingleObjectEx(wsa_event, (DWORD)(stop_time - current_time), FALSE); - WSACloseEvent(wsa_event); - - if (ret != WAIT_OBJECT_0) { - return FALSE; - } - - return TRUE; + return true; } -bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout) +bool hdhomerun_sock_send(struct hdhomerun_sock_t *sock, const void *data, size_t length, uint64_t timeout) { + if (!hdhomerun_sock_event_select(sock, FD_WRITE | FD_CLOSE)) { + return false; + } + uint64_t stop_time = getcurrenttime() + timeout; const uint8_t *ptr = (uint8_t *)data; while (1) { - int ret = send(sock, (char *)ptr, (int)length, 0); + int ret = send(sock->sock, (char *)ptr, (int)length, 0); if (ret >= (int)length) { - return TRUE; + return true; + } + + if ((ret == SOCKET_ERROR) && (WSAGetLastError() != WSAEWOULDBLOCK)) { + return false; } if (ret > 0) { @@ -256,92 +409,121 @@ bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t lengt length -= ret; } - if (WSAGetLastError() != WSAEWOULDBLOCK) { - return FALSE; + uint64_t current_time = getcurrenttime(); + if (current_time >= stop_time) { + return false; } - if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) { - return FALSE; + if (WaitForSingleObjectEx(sock->event, (DWORD)(stop_time - current_time), false) != WAIT_OBJECT_0) { + return false; } } } -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) +bool hdhomerun_sock_sendto(struct hdhomerun_sock_t *sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout) { - uint64_t stop_time = getcurrenttime() + timeout; - const uint8_t *ptr = (uint8_t *)data; + if (!hdhomerun_sock_event_select(sock, FD_WRITE | FD_CLOSE)) { + return false; + } - while (1) { - struct sockaddr_in sock_addr; - memset(&sock_addr, 0, sizeof(sock_addr)); - sock_addr.sin_family = AF_INET; - sock_addr.sin_addr.s_addr = htonl(remote_addr); - sock_addr.sin_port = htons(remote_port); + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = htonl(remote_addr); + sock_addr.sin_port = htons(remote_port); - int ret = sendto(sock, (char *)ptr, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); - if (ret >= (int)length) { - return TRUE; - } + int ret = sendto(sock->sock, (char *)data, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); + if (ret >= (int)length) { + return true; + } - if (ret > 0) { - ptr += ret; - length -= ret; - } + if (ret >= 0) { + return false; + } + if (WSAGetLastError() != WSAEWOULDBLOCK) { + return false; + } - if (WSAGetLastError() != WSAEWOULDBLOCK) { - return FALSE; - } + if (WaitForSingleObjectEx(sock->event, (DWORD)timeout, false) != WAIT_OBJECT_0) { + return false; + } - if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) { - return FALSE; - } + ret = sendto(sock->sock, (char *)data, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); + if (ret >= (int)length) { + return true; } + + return false; } -bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout) +bool hdhomerun_sock_recv(struct hdhomerun_sock_t *sock, void *data, size_t *length, uint64_t timeout) { - uint64_t stop_time = getcurrenttime() + timeout; + if (!hdhomerun_sock_event_select(sock, FD_READ | FD_CLOSE)) { + return false; + } - while (1) { - int ret = recv(sock, (char *)data, (int)(*length), 0); - if (ret > 0) { - *length = ret; - return TRUE; - } + int ret = recv(sock->sock, (char *)data, (int)(*length), 0); + if (ret > 0) { + *length = ret; + return true; + } - if (WSAGetLastError() != WSAEWOULDBLOCK) { - return FALSE; - } + if (ret == 0) { + return false; + } + if (WSAGetLastError() != WSAEWOULDBLOCK) { + return false; + } - if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) { - return FALSE; - } + if (WaitForSingleObjectEx(sock->event, (DWORD)timeout, false) != WAIT_OBJECT_0) { + return false; } + + ret = recv(sock->sock, (char *)data, (int)(*length), 0); + if (ret > 0) { + *length = ret; + return true; + } + + return false; } -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) +bool hdhomerun_sock_recvfrom(struct hdhomerun_sock_t *sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout) { - uint64_t stop_time = getcurrenttime() + timeout; + if (!hdhomerun_sock_event_select(sock, FD_READ | FD_CLOSE)) { + return false; + } - while (1) { - struct sockaddr_in sock_addr; - memset(&sock_addr, 0, sizeof(sock_addr)); - int sockaddr_size = sizeof(sock_addr); + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); + int sockaddr_size = sizeof(sock_addr); - int ret = recvfrom(sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size); - if (ret > 0) { - *remote_addr = ntohl(sock_addr.sin_addr.s_addr); - *remote_port = ntohs(sock_addr.sin_port); - *length = ret; - return TRUE; - } + int ret = recvfrom(sock->sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size); + if (ret > 0) { + *remote_addr = ntohl(sock_addr.sin_addr.s_addr); + *remote_port = ntohs(sock_addr.sin_port); + *length = ret; + return true; + } - if (WSAGetLastError() != WSAEWOULDBLOCK) { - return FALSE; - } + if (ret == 0) { + return false; + } + if (WSAGetLastError() != WSAEWOULDBLOCK) { + return false; + } - if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) { - return FALSE; - } + if (WaitForSingleObjectEx(sock->event, (DWORD)timeout, false) != WAIT_OBJECT_0) { + return false; } + + ret = recvfrom(sock->sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size); + if (ret > 0) { + *remote_addr = ntohl(sock_addr.sin_addr.s_addr); + *remote_port = ntohs(sock_addr.sin_port); + *length = ret; + return true; + } + + return false; } diff --git a/libhdhomerun/hdhomerun_types.h b/libhdhomerun/hdhomerun_types.h index bb12308..cf98001 100644 --- a/libhdhomerun/hdhomerun_types.h +++ b/libhdhomerun/hdhomerun_types.h @@ -1,12 +1,12 @@ /* * hdhomerun_types.h * - * Copyright © 2008-2009 Silicondust USA Inc. . + * Copyright © 2008-2015 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define HDHOMERUN_STATUS_COLOR_NEUTRAL 0xFFFFFFFF @@ -41,9 +29,9 @@ struct hdhomerun_device_allocation_t; struct hdhomerun_tuner_status_t { char channel[32]; char lock_str[32]; - bool_t signal_present; - bool_t lock_supported; - bool_t lock_unsupported; + bool signal_present; + bool lock_supported; + bool lock_unsupported; unsigned int signal_strength; unsigned int signal_to_noise_quality; unsigned int symbol_error_quality; @@ -51,6 +39,17 @@ struct hdhomerun_tuner_status_t { uint32_t packets_per_second; }; +struct hdhomerun_tuner_vstatus_t { + char vchannel[32]; + char name[32]; + char auth[32]; + char cci[32]; + char cgms[32]; + bool not_subscribed; + bool not_available; + bool copy_protected; +}; + struct hdhomerun_channelscan_program_t { char program_str[64]; uint16_t program_number; @@ -69,8 +68,10 @@ struct hdhomerun_channelscan_result_t { struct hdhomerun_tuner_status_t status; int program_count; struct hdhomerun_channelscan_program_t programs[HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT]; - bool_t transport_stream_id_detected; + bool transport_stream_id_detected; + bool original_network_id_detected; uint16_t transport_stream_id; + uint16_t original_network_id; }; struct hdhomerun_plotsample_t { diff --git a/libhdhomerun/hdhomerun_video.c b/libhdhomerun/hdhomerun_video.c index 6bd3412..9db03ca 100644 --- a/libhdhomerun/hdhomerun_video.c +++ b/libhdhomerun/hdhomerun_video.c @@ -1,12 +1,12 @@ /* * hdhomerun_video.c * - * Copyright © 2006-2010 Silicondust USA Inc. . + * Copyright © 2006-2016 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,30 +14,21 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hdhomerun.h" struct hdhomerun_video_sock_t { - pthread_mutex_t lock; + thread_mutex_t lock; struct hdhomerun_debug_t *dbg; + struct hdhomerun_sock_t *sock; - hdhomerun_sock_t sock; - uint32_t multicast_ip; + uint32_t keepalive_lockkey; + uint32_t keepalive_addr; + uint16_t keepalive_port; + volatile bool keepalive_start; volatile size_t head; volatile size_t tail; @@ -45,8 +36,8 @@ struct hdhomerun_video_sock_t { size_t buffer_size; size_t advance; - pthread_t thread; - volatile bool_t terminate; + thread_task_t thread; + volatile bool terminate; volatile uint32_t packet_count; volatile uint32_t transport_error_count; @@ -58,9 +49,9 @@ struct hdhomerun_video_sock_t { volatile uint8_t sequence[0x2000]; }; -static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg); +static void hdhomerun_video_thread_execute(void *arg); -struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size, struct hdhomerun_debug_t *dbg) +struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, bool allow_port_reuse, size_t buffer_size, struct hdhomerun_debug_t *dbg) { /* Create object. */ struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)calloc(1, sizeof(struct hdhomerun_video_sock_t)); @@ -70,8 +61,7 @@ struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size } vs->dbg = dbg; - vs->sock = HDHOMERUN_SOCK_INVALID; - pthread_mutex_init(&vs->lock, NULL); + thread_mutex_init(&vs->lock); /* Reset sequence tracking. */ hdhomerun_video_flush(vs); @@ -93,23 +83,22 @@ struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size /* Create socket. */ vs->sock = hdhomerun_sock_create_udp(); - if (vs->sock == HDHOMERUN_SOCK_INVALID) { + if (!vs->sock) { hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate socket\n"); goto error; } /* Expand socket buffer size. */ - int rx_size = 1024 * 1024; - setsockopt(vs->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rx_size, sizeof(rx_size)); + hdhomerun_sock_set_recv_buffer_size(vs->sock, 1024 * 1024); /* Bind socket. */ - if (!hdhomerun_sock_bind(vs->sock, INADDR_ANY, listen_port)) { + if (!hdhomerun_sock_bind(vs->sock, INADDR_ANY, listen_port, allow_port_reuse)) { hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to bind socket (port %u)\n", listen_port); goto error; } /* Start thread. */ - if (pthread_create(&vs->thread, NULL, &hdhomerun_video_thread_execute, vs) != 0) { + if (!thread_task_create(&vs->thread, &hdhomerun_video_thread_execute, vs)) { hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to start thread\n"); goto error; } @@ -118,28 +107,48 @@ struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size return vs; error: - if (vs->sock != HDHOMERUN_SOCK_INVALID) { + if (vs->sock) { hdhomerun_sock_destroy(vs->sock); } + if (vs->buffer) { free(vs->buffer); } + + thread_mutex_dispose(&vs->lock); + free(vs); return NULL; } void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs) { - vs->terminate = TRUE; - pthread_join(vs->thread, NULL); + vs->terminate = true; + thread_task_join(vs->thread); hdhomerun_sock_destroy(vs->sock); + thread_mutex_dispose(&vs->lock); free(vs->buffer); free(vs); } -hdhomerun_sock_t hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs) +void hdhomerun_video_set_keepalive(struct hdhomerun_video_sock_t *vs, uint32_t remote_addr, uint16_t remote_port, uint32_t lockkey) +{ + thread_mutex_lock(&vs->lock); + + vs->keepalive_addr = remote_addr; + vs->keepalive_port = remote_port; + vs->keepalive_lockkey = lockkey; + + if ((remote_addr != 0) && (remote_port != 0)) { + vs->keepalive_start = true; + } + + thread_mutex_unlock(&vs->lock); +} + +struct hdhomerun_sock_t *hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs) { return vs->sock; } @@ -157,41 +166,19 @@ uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs) int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip) { - if (vs->multicast_ip != 0) { - hdhomerun_video_leave_multicast_group(vs); - } - - struct ip_mreq imr; - memset(&imr, 0, sizeof(imr)); - imr.imr_multiaddr.s_addr = htonl(multicast_ip); - imr.imr_interface.s_addr = htonl(local_ip); - - if (setsockopt(vs->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { + if (!hdhomerun_sock_join_multicast_group(vs->sock, multicast_ip, local_ip)) { hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_join_multicast_group: setsockopt failed (%d)\n", hdhomerun_sock_getlasterror()); return -1; } - vs->multicast_ip = multicast_ip; return 1; } -int hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs) +void hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip) { - if (vs->multicast_ip == 0) { - return 1; - } - - struct ip_mreq imr; - memset(&imr, 0, sizeof(imr)); - imr.imr_multiaddr.s_addr = htonl(vs->multicast_ip); - imr.imr_interface.s_addr = htonl(INADDR_ANY); - - if (setsockopt(vs->sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(imr)) != 0) { + if (!hdhomerun_sock_leave_multicast_group(vs->sock, multicast_ip, local_ip)) { hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_leave_multicast_group: setsockopt failed (%d)\n", hdhomerun_sock_getlasterror()); } - - vs->multicast_ip = 0; - return 1; } static void hdhomerun_video_stats_ts_pkt(struct hdhomerun_video_sock_t *vs, uint8_t *ptr) @@ -201,7 +188,7 @@ static void hdhomerun_video_stats_ts_pkt(struct hdhomerun_video_sock_t *vs, uint return; } - bool_t transport_error = ptr[1] >> 7; + bool transport_error = ptr[1] >> 7; if (transport_error) { vs->transport_error_count++; vs->sequence[packet_identifier] = 0xFF; @@ -255,26 +242,51 @@ static void hdhomerun_video_parse_rtp(struct hdhomerun_video_sock_t *vs, struct } } -static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg) +static void hdhomerun_video_thread_send_keepalive(struct hdhomerun_video_sock_t *vs) +{ + thread_mutex_lock(&vs->lock); + uint32_t keepalive_lockkey = vs->keepalive_lockkey; + uint32_t keepalive_addr = vs->keepalive_addr; + uint16_t keepalive_port = vs->keepalive_port; + vs->keepalive_start = false; + thread_mutex_unlock(&vs->lock); + + if ((keepalive_addr == 0) || (keepalive_port == 0)) { + return; + } + + struct hdhomerun_pkt_t pkt; + hdhomerun_pkt_reset(&pkt); + hdhomerun_pkt_write_u32(&pkt, keepalive_lockkey); + hdhomerun_sock_sendto(vs->sock, keepalive_addr, keepalive_port, pkt.start, pkt.end - pkt.start, 25); +} + +static void hdhomerun_video_thread_execute(void *arg) { struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)arg; - struct hdhomerun_pkt_t pkt_inst; + uint64_t send_time = getcurrenttime(); while (!vs->terminate) { - struct hdhomerun_pkt_t *pkt = &pkt_inst; - hdhomerun_pkt_reset(pkt); + uint64_t current_time = getcurrenttime(); + if (vs->keepalive_start || (current_time >= send_time)) { + hdhomerun_video_thread_send_keepalive(vs); + send_time = current_time + 1000; + } /* Receive. */ + struct hdhomerun_pkt_t pkt; + hdhomerun_pkt_reset(&pkt); + size_t length = VIDEO_RTP_DATA_PACKET_SIZE; - if (!hdhomerun_sock_recv(vs->sock, pkt->end, &length, 25)) { + if (!hdhomerun_sock_recv(vs->sock, pkt.end, &length, 25)) { continue; } - pkt->end += length; + pkt.end += length; if (length == VIDEO_RTP_DATA_PACKET_SIZE) { - hdhomerun_video_parse_rtp(vs, pkt); - length = (int)(pkt->end - pkt->pos); + hdhomerun_video_parse_rtp(vs, &pkt); + length = pkt.end - pkt.pos; } if (length != VIDEO_DATA_PACKET_SIZE) { @@ -282,12 +294,12 @@ static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg) continue; } - pthread_mutex_lock(&vs->lock); + thread_mutex_lock(&vs->lock); /* Store in ring buffer. */ size_t head = vs->head; uint8_t *ptr = vs->buffer + head; - memcpy(ptr, pkt->pos, length); + memcpy(ptr, pkt.pos, length); /* Stats. */ vs->packet_count++; @@ -308,21 +320,19 @@ static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg) /* Check for buffer overflow. */ if (head == vs->tail) { vs->overflow_error_count++; - pthread_mutex_unlock(&vs->lock); + thread_mutex_unlock(&vs->lock); continue; } vs->head = head; - pthread_mutex_unlock(&vs->lock); + thread_mutex_unlock(&vs->lock); } - - return NULL; } uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size) { - pthread_mutex_lock(&vs->lock); + thread_mutex_lock(&vs->lock); size_t head = vs->head; size_t tail = vs->tail; @@ -339,7 +349,7 @@ uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size if (head == tail) { vs->advance = 0; *pactual_size = 0; - pthread_mutex_unlock(&vs->lock); + thread_mutex_unlock(&vs->lock); return NULL; } @@ -347,7 +357,7 @@ uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size if (size == 0) { vs->advance = 0; *pactual_size = 0; - pthread_mutex_unlock(&vs->lock); + thread_mutex_unlock(&vs->lock); return NULL; } @@ -364,13 +374,13 @@ uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size *pactual_size = size; uint8_t *result = vs->buffer + tail; - pthread_mutex_unlock(&vs->lock); + thread_mutex_unlock(&vs->lock); return result; } void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs) { - pthread_mutex_lock(&vs->lock); + thread_mutex_lock(&vs->lock); vs->tail = vs->head; vs->advance = 0; @@ -388,7 +398,7 @@ void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs) vs->sequence_error_count = 0; vs->overflow_error_count = 0; - pthread_mutex_unlock(&vs->lock); + thread_mutex_unlock(&vs->lock); } void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs) @@ -396,10 +406,10 @@ void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs) struct hdhomerun_video_stats_t stats; hdhomerun_video_get_stats(vs, &stats); - hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%lu net=%lu te=%lu miss=%lu drop=%lu\n", - (unsigned long)stats.packet_count, (unsigned long)stats.network_error_count, - (unsigned long)stats.transport_error_count, (unsigned long)stats.sequence_error_count, - (unsigned long)stats.overflow_error_count + hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%u net=%u te=%u miss=%u drop=%u\n", + (unsigned int)stats.packet_count, (unsigned int)stats.network_error_count, + (unsigned int)stats.transport_error_count, (unsigned int)stats.sequence_error_count, + (unsigned int)stats.overflow_error_count ); } @@ -407,7 +417,7 @@ void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomer { memset(stats, 0, sizeof(struct hdhomerun_video_stats_t)); - pthread_mutex_lock(&vs->lock); + thread_mutex_lock(&vs->lock); stats->packet_count = vs->packet_count; stats->network_error_count = vs->network_error_count; @@ -415,5 +425,5 @@ void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomer stats->sequence_error_count = vs->sequence_error_count; stats->overflow_error_count = vs->overflow_error_count; - pthread_mutex_unlock(&vs->lock); + thread_mutex_unlock(&vs->lock); } diff --git a/libhdhomerun/hdhomerun_video.h b/libhdhomerun/hdhomerun_video.h index 4fa9f79..863547a 100644 --- a/libhdhomerun/hdhomerun_video.h +++ b/libhdhomerun/hdhomerun_video.h @@ -1,12 +1,12 @@ /* * hdhomerun_video.h * - * Copyright © 2006 Silicondust USA Inc. . + * Copyright © 2006-2016 Silicondust USA Inc. . * - * This library is free software; you can redistribute it and/or + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,20 +14,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * As a special exception to the GNU Lesser General Public License, - * you may link, statically or dynamically, an application with a - * publicly distributed version of the Library to produce an - * executable file containing portions of the Library, and - * distribute that executable file under terms of your choice, - * without any of the additional requirements listed in clause 4 of - * the GNU Lesser General Public License. - * - * By "a publicly distributed version of the Library", we mean - * either the unmodified Library as distributed by Silicondust, or a - * modified version of the Library that is distributed under the - * conditions defined in the GNU Lesser General Public License. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus extern "C" { @@ -60,21 +48,26 @@ struct hdhomerun_video_stats_t { * * When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy. */ -extern LIBTYPE struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size, struct hdhomerun_debug_t *dbg); -extern LIBTYPE void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs); +extern LIBHDHOMERUN_API struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, bool allow_port_reuse, size_t buffer_size, struct hdhomerun_debug_t *dbg); +extern LIBHDHOMERUN_API void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs); + +/* + * Configure to send a keepalive packet every second. + */ +extern LIBHDHOMERUN_API void hdhomerun_video_set_keepalive(struct hdhomerun_video_sock_t *vs, uint32_t remote_addr, uint16_t remote_port, uint32_t lockkey); /* * Get the port the socket is listening on. * * Returns 16-bit port with native endianness, or 0 on error. */ -extern LIBTYPE uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs); +extern LIBHDHOMERUN_API uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs); /* * Join/leave multicast group. */ -extern LIBTYPE int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip); -extern LIBTYPE int hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs); +extern LIBHDHOMERUN_API int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip); +extern LIBHDHOMERUN_API void hdhomerun_video_leave_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip); /* * Read data from buffer. @@ -93,23 +86,23 @@ extern LIBTYPE int hdhomerun_video_leave_multicast_group(struct hdhomerun_video_ * The buffer is implemented as a ring buffer. It is possible for this function to return a small * amount of data when more is available due to the wrap-around case. */ -extern LIBTYPE uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size); +extern LIBHDHOMERUN_API uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size); /* * Flush the buffer. */ -extern LIBTYPE void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs); +extern LIBHDHOMERUN_API void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs); /* * Debug print internal stats. */ -extern LIBTYPE void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs); -extern LIBTYPE void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomerun_video_stats_t *stats); +extern LIBHDHOMERUN_API void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs); +extern LIBHDHOMERUN_API void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomerun_video_stats_t *stats); /* * Internal use only. */ -extern LIBTYPE hdhomerun_sock_t hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs); +extern LIBHDHOMERUN_API struct hdhomerun_sock_t *hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs); #ifdef __cplusplus }