00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "hdhomerun.h"
00034
00035 struct hdhomerun_device_selector_t {
00036 struct hdhomerun_device_t **hd_list;
00037 size_t hd_count;
00038 struct hdhomerun_debug_t *dbg;
00039 };
00040
00041 struct hdhomerun_device_selector_t *hdhomerun_device_selector_create(struct hdhomerun_debug_t *dbg)
00042 {
00043 struct hdhomerun_device_selector_t *hds = (struct hdhomerun_device_selector_t *)calloc(1, sizeof(struct hdhomerun_device_selector_t));
00044 if (!hds) {
00045 hdhomerun_debug_printf(dbg, "hdhomerun_device_selector_create: failed to allocate selector object\n");
00046 return NULL;
00047 }
00048
00049 hds->dbg = dbg;
00050
00051 return hds;
00052 }
00053
00054 void hdhomerun_device_selector_destroy(struct hdhomerun_device_selector_t *hds, bool_t destroy_devices)
00055 {
00056 if (destroy_devices) {
00057 size_t index;
00058 for (index = 0; index < hds->hd_count; index++) {
00059 struct hdhomerun_device_t *entry = hds->hd_list[index];
00060 hdhomerun_device_destroy(entry);
00061 }
00062 }
00063
00064 if (hds->hd_list) {
00065 free(hds->hd_list);
00066 }
00067
00068 free(hds);
00069 }
00070
00071 LIBTYPE int hdhomerun_device_selector_get_device_count(struct hdhomerun_device_selector_t *hds)
00072 {
00073 return (int)hds->hd_count;
00074 }
00075
00076 void hdhomerun_device_selector_add_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd)
00077 {
00078 size_t index;
00079 for (index = 0; index < hds->hd_count; index++) {
00080 struct hdhomerun_device_t *entry = hds->hd_list[index];
00081 if (entry == hd) {
00082 return;
00083 }
00084 }
00085
00086 hds->hd_list = (struct hdhomerun_device_t **)realloc(hds->hd_list, (hds->hd_count + 1) * sizeof(struct hdhomerun_device_selector_t *));
00087 if (!hds->hd_list) {
00088 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_add_device: failed to allocate device list\n");
00089 return;
00090 }
00091
00092 hds->hd_list[hds->hd_count++] = hd;
00093 }
00094
00095 void hdhomerun_device_selector_remove_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd)
00096 {
00097 size_t index = 0;
00098 while (1) {
00099 if (index >= hds->hd_count) {
00100 return;
00101 }
00102
00103 struct hdhomerun_device_t *entry = hds->hd_list[index];
00104 if (entry == hd) {
00105 break;
00106 }
00107
00108 index++;
00109 }
00110
00111 while (index + 1 < hds->hd_count) {
00112 hds->hd_list[index] = hds->hd_list[index + 1];
00113 index++;
00114 }
00115
00116 hds->hd_list[index] = NULL;
00117 hds->hd_count--;
00118 }
00119
00120 struct hdhomerun_device_t *hdhomerun_device_selector_find_device(struct hdhomerun_device_selector_t *hds, uint32_t device_id, unsigned int tuner_index)
00121 {
00122 size_t index;
00123 for (index = 0; index < hds->hd_count; index++) {
00124 struct hdhomerun_device_t *entry = hds->hd_list[index];
00125 if (hdhomerun_device_get_device_id(entry) != device_id) {
00126 continue;
00127 }
00128 if (hdhomerun_device_get_tuner(entry) != tuner_index) {
00129 continue;
00130 }
00131 return entry;
00132 }
00133
00134 return NULL;
00135 }
00136
00137 int hdhomerun_device_selector_load_from_file(struct hdhomerun_device_selector_t *hds, char *filename)
00138 {
00139 FILE *fp = fopen(filename, "r");
00140 if (!fp) {
00141 return 0;
00142 }
00143
00144 while(1) {
00145 char device_name[32];
00146 if (!fgets(device_name, sizeof(device_name), fp)) {
00147 break;
00148 }
00149
00150 struct hdhomerun_device_t *hd = hdhomerun_device_create_from_str(device_name, hds->dbg);
00151 if (!hd) {
00152 continue;
00153 }
00154
00155 hdhomerun_device_selector_add_device(hds, hd);
00156 }
00157
00158 fclose(fp);
00159 return (int)hds->hd_count;
00160 }
00161
00162 #if defined(__WINDOWS__)
00163 int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource)
00164 {
00165 HKEY tuners_key;
00166 LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Silicondust\\HDHomeRun\\Tuners", 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &tuners_key);
00167 if (ret != ERROR_SUCCESS) {
00168 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open tuners registry key (%ld)\n", (long)ret);
00169 return 0;
00170 }
00171
00172 DWORD index = 0;
00173 while (1) {
00174
00175 wchar_t wdevice_name[32];
00176 DWORD size = sizeof(wdevice_name);
00177 ret = RegEnumKeyEx(tuners_key, index++, wdevice_name, &size, NULL, NULL, NULL, NULL);
00178 if (ret != ERROR_SUCCESS) {
00179 break;
00180 }
00181
00182
00183 HKEY device_key;
00184 ret = RegOpenKeyEx(tuners_key, wdevice_name, 0, KEY_QUERY_VALUE, &device_key);
00185 if (ret != ERROR_SUCCESS) {
00186 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);
00187 continue;
00188 }
00189
00190 wchar_t wsource_test[32];
00191 size = sizeof(wsource_test);
00192 if (RegQueryValueEx(device_key, L"Source", NULL, NULL, (LPBYTE)&wsource_test, &size) != ERROR_SUCCESS) {
00193 wsprintf(wsource_test, L"Unknown");
00194 }
00195
00196 RegCloseKey(device_key);
00197
00198 if (_wcsicmp(wsource_test, wsource) != 0) {
00199 continue;
00200 }
00201
00202
00203 char device_name[32];
00204 sprintf(device_name, "%S", wdevice_name);
00205
00206 struct hdhomerun_device_t *hd = hdhomerun_device_create_from_str(device_name, hds->dbg);
00207 if (!hd) {
00208 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: invalid device name '%s' / failed to create device object\n", device_name);
00209 continue;
00210 }
00211
00212 hdhomerun_device_selector_add_device(hds, hd);
00213 }
00214
00215 RegCloseKey(tuners_key);
00216 return (int)hds->hd_count;
00217 }
00218 #endif
00219
00220 static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *test_hd)
00221 {
00222 const char *name = hdhomerun_device_get_name(test_hd);
00223
00224
00225
00226
00227 char *error;
00228 int ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
00229 if (ret > 0) {
00230 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
00231 return TRUE;
00232 }
00233 if (ret < 0) {
00234 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
00235 return FALSE;
00236 }
00237
00238
00239
00240
00241 char *target;
00242 ret = hdhomerun_device_get_tuner_target(test_hd, &target);
00243 if (ret < 0) {
00244 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
00245 return FALSE;
00246 }
00247 if (ret == 0) {
00248 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to read target\n", name);
00249 return FALSE;
00250 }
00251
00252 char *ptr = strstr(target, "//");
00253 if (ptr) {
00254 target = ptr + 2;
00255 }
00256 ptr = strchr(target, ' ');
00257 if (ptr) {
00258 *ptr = 0;
00259 }
00260
00261 unsigned long a[4];
00262 unsigned long target_port;
00263 if (sscanf(target, "%lu.%lu.%lu.%lu:%lu", &a[0], &a[1], &a[2], &a[3], &target_port) != 5) {
00264 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, no target set (%s)\n", name, target);
00265 return FALSE;
00266 }
00267
00268 uint32_t target_ip = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
00269 uint32_t local_ip = hdhomerun_device_get_local_machine_addr(test_hd);
00270 if (target_ip != local_ip) {
00271 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by %s\n", name, target);
00272 return FALSE;
00273 }
00274
00275
00276
00277
00278 hdhomerun_sock_t test_sock = hdhomerun_sock_create_udp();
00279 if (test_sock == HDHOMERUN_SOCK_INVALID) {
00280 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to create test sock\n", name);
00281 return FALSE;
00282 }
00283
00284 bool_t inuse = (hdhomerun_sock_bind(test_sock, INADDR_ANY, (uint16_t)target_port, FALSE) == FALSE);
00285 hdhomerun_sock_destroy(test_sock);
00286
00287 if (inuse) {
00288 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine\n", name);
00289 return FALSE;
00290 }
00291
00292
00293
00294
00295 ret = hdhomerun_device_tuner_lockkey_force(test_hd);
00296 if (ret < 0) {
00297 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
00298 return FALSE;
00299 }
00300 if (ret == 0) {
00301 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);
00302 return FALSE;
00303 }
00304
00305 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, lockkey force successful\n", name);
00306
00307
00308
00309
00310 ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
00311 if (ret > 0) {
00312 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
00313 return TRUE;
00314 }
00315 if (ret < 0) {
00316 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
00317 return FALSE;
00318 }
00319
00320 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s still in use after lockkey force (%s)\n", name, error);
00321 return FALSE;
00322 }
00323
00324 struct hdhomerun_device_t *hdhomerun_device_selector_choose_and_lock(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *prefered)
00325 {
00326
00327 if (prefered) {
00328 if (hdhomerun_device_selector_choose_test(hds, prefered)) {
00329 return prefered;
00330 }
00331 }
00332
00333
00334 size_t index;
00335 for (index = 0; index < hds->hd_count; index++) {
00336 struct hdhomerun_device_t *entry = hds->hd_list[index];
00337 if (entry == prefered) {
00338 continue;
00339 }
00340
00341 if (hdhomerun_device_selector_choose_test(hds, entry)) {
00342 return entry;
00343 }
00344 }
00345
00346 hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_and_lock: no devices available\n");
00347 return NULL;
00348 }