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 #define HDHOMERUN_DISOCVER_MAX_SOCK_COUNT 16
00036
00037 struct hdhomerun_discover_sock_t {
00038 hdhomerun_sock_t sock;
00039 bool_t detected;
00040 uint32_t local_ip;
00041 uint32_t subnet_mask;
00042 };
00043
00044 struct hdhomerun_discover_t {
00045 struct hdhomerun_discover_sock_t socks[HDHOMERUN_DISOCVER_MAX_SOCK_COUNT];
00046 unsigned int sock_count;
00047 struct hdhomerun_pkt_t tx_pkt;
00048 struct hdhomerun_pkt_t rx_pkt;
00049 };
00050
00051 static bool_t hdhomerun_discover_sock_add(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
00052 {
00053 unsigned int i;
00054 for (i = 1; i < ds->sock_count; i++) {
00055 struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
00056
00057 if ((dss->local_ip == local_ip) && (dss->subnet_mask == subnet_mask)) {
00058 dss->detected = TRUE;
00059 return TRUE;
00060 }
00061 }
00062
00063 if (ds->sock_count >= HDHOMERUN_DISOCVER_MAX_SOCK_COUNT) {
00064 return FALSE;
00065 }
00066
00067
00068 hdhomerun_sock_t sock = hdhomerun_sock_create_udp();
00069 if (sock == HDHOMERUN_SOCK_INVALID) {
00070 return FALSE;
00071 }
00072
00073
00074 if (!hdhomerun_sock_bind(sock, local_ip, 0, FALSE)) {
00075 hdhomerun_sock_destroy(sock);
00076 return FALSE;
00077 }
00078
00079
00080 struct hdhomerun_discover_sock_t *dss = &ds->socks[ds->sock_count++];
00081 dss->sock = sock;
00082 dss->detected = TRUE;
00083 dss->local_ip = local_ip;
00084 dss->subnet_mask = subnet_mask;
00085
00086 return TRUE;
00087 }
00088
00089 struct hdhomerun_discover_t *hdhomerun_discover_create(void)
00090 {
00091 struct hdhomerun_discover_t *ds = (struct hdhomerun_discover_t *)calloc(1, sizeof(struct hdhomerun_discover_t));
00092 if (!ds) {
00093 return NULL;
00094 }
00095
00096
00097 if (!hdhomerun_discover_sock_add(ds, 0, 0)) {
00098 free(ds);
00099 return NULL;
00100 }
00101
00102
00103 return ds;
00104 }
00105
00106 void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds)
00107 {
00108 unsigned int i;
00109 for (i = 0; i < ds->sock_count; i++) {
00110 struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
00111 hdhomerun_sock_destroy(dss->sock);
00112 }
00113
00114 free(ds);
00115 }
00116
00117 static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
00118 {
00119 unsigned int i;
00120 for (i = 1; i < ds->sock_count; i++) {
00121 struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
00122 dss->detected = FALSE;
00123 }
00124
00125 struct hdhomerun_local_ip_info_t ip_info_list[HDHOMERUN_DISOCVER_MAX_SOCK_COUNT];
00126 int count = hdhomerun_local_ip_info(ip_info_list, HDHOMERUN_DISOCVER_MAX_SOCK_COUNT);
00127 if (count < 0) {
00128 count = 0;
00129 }
00130
00131 int index;
00132 for (index = 0; index < count; index++) {
00133 struct hdhomerun_local_ip_info_t *ip_info = &ip_info_list[index];
00134 hdhomerun_discover_sock_add(ds, ip_info->ip_addr, ip_info->subnet_mask);
00135 }
00136
00137 struct hdhomerun_discover_sock_t *src = &ds->socks[1];
00138 struct hdhomerun_discover_sock_t *dst = &ds->socks[1];
00139 count = 1;
00140 for (i = 1; i < ds->sock_count; i++) {
00141 if (!src->detected) {
00142 hdhomerun_sock_destroy(src->sock);
00143 src++;
00144 continue;
00145 }
00146 if (dst != src) {
00147 *dst = *src;
00148 }
00149 src++;
00150 dst++;
00151 count++;
00152 }
00153
00154 ds->sock_count = count;
00155 }
00156
00157 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)
00158 {
00159 struct hdhomerun_pkt_t *tx_pkt = &ds->tx_pkt;
00160 hdhomerun_pkt_reset(tx_pkt);
00161
00162 hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_DEVICE_TYPE);
00163 hdhomerun_pkt_write_var_length(tx_pkt, 4);
00164 hdhomerun_pkt_write_u32(tx_pkt, device_type);
00165 hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_DEVICE_ID);
00166 hdhomerun_pkt_write_var_length(tx_pkt, 4);
00167 hdhomerun_pkt_write_u32(tx_pkt, device_id);
00168 hdhomerun_pkt_seal_frame(tx_pkt, HDHOMERUN_TYPE_DISCOVER_REQ);
00169
00170 return hdhomerun_sock_sendto(dss->sock, target_ip, HDHOMERUN_DISCOVER_UDP_PORT, tx_pkt->start, tx_pkt->end - tx_pkt->start, 0);
00171 }
00172
00173 static bool_t hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id)
00174 {
00175 bool_t result = FALSE;
00176
00177
00178
00179
00180
00181 unsigned int i;
00182 for (i = 1; i < ds->sock_count; i++) {
00183 struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
00184 uint32_t target_ip = dss->local_ip | ~dss->subnet_mask;
00185 result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
00186 }
00187
00188
00189
00190
00191 if (!result) {
00192 struct hdhomerun_discover_sock_t *dss = &ds->socks[0];
00193 result = hdhomerun_discover_send_internal(ds, dss, 0xFFFFFFFF, device_type, device_id);
00194 }
00195
00196 return result;
00197 }
00198
00199 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)
00200 {
00201 bool_t result = FALSE;
00202
00203
00204
00205
00206
00207 unsigned int i;
00208 for (i = 1; i < ds->sock_count; i++) {
00209 struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
00210 if ((target_ip & dss->subnet_mask) != (dss->local_ip & dss->subnet_mask)) {
00211 continue;
00212 }
00213
00214 result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
00215 }
00216
00217
00218
00219
00220 if (!result) {
00221 struct hdhomerun_discover_sock_t *dss = &ds->socks[0];
00222 result = hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
00223 }
00224
00225 return result;
00226 }
00227
00228 static bool_t hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id)
00229 {
00230 if (target_ip == 0) {
00231 return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id);
00232 } else {
00233 return hdhomerun_discover_send_target_ip(ds, target_ip, device_type, device_id);
00234 }
00235 }
00236
00237 static bool_t hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result)
00238 {
00239 struct hdhomerun_pkt_t *rx_pkt = &ds->rx_pkt;
00240 hdhomerun_pkt_reset(rx_pkt);
00241
00242 uint32_t remote_addr;
00243 uint16_t remote_port;
00244 size_t length = rx_pkt->limit - rx_pkt->end;
00245 if (!hdhomerun_sock_recvfrom(dss->sock, &remote_addr, &remote_port, rx_pkt->end, &length, 0)) {
00246 return FALSE;
00247 }
00248
00249 rx_pkt->end += length;
00250
00251 uint16_t type;
00252 if (hdhomerun_pkt_open_frame(rx_pkt, &type) <= 0) {
00253 return FALSE;
00254 }
00255 if (type != HDHOMERUN_TYPE_DISCOVER_RPY) {
00256 return FALSE;
00257 }
00258
00259 result->ip_addr = remote_addr;
00260 result->device_type = 0;
00261 result->device_id = 0;
00262 result->tuner_count = 0;
00263
00264 while (1) {
00265 uint8_t tag;
00266 size_t len;
00267 uint8_t *next = hdhomerun_pkt_read_tlv(rx_pkt, &tag, &len);
00268 if (!next) {
00269 break;
00270 }
00271
00272 switch (tag) {
00273 case HDHOMERUN_TAG_DEVICE_TYPE:
00274 if (len != 4) {
00275 break;
00276 }
00277 result->device_type = hdhomerun_pkt_read_u32(rx_pkt);
00278 break;
00279
00280 case HDHOMERUN_TAG_DEVICE_ID:
00281 if (len != 4) {
00282 break;
00283 }
00284 result->device_id = hdhomerun_pkt_read_u32(rx_pkt);
00285 break;
00286
00287 case HDHOMERUN_TAG_TUNER_COUNT:
00288 if (len != 1) {
00289 break;
00290 }
00291 result->tuner_count = hdhomerun_pkt_read_u8(rx_pkt);
00292 break;
00293
00294 default:
00295 break;
00296 }
00297
00298 rx_pkt->pos = next;
00299 }
00300
00301
00302 if (result->tuner_count == 0) {
00303 switch (result->device_id >> 20) {
00304 case 0x102:
00305 result->tuner_count = 1;
00306 break;
00307
00308 case 0x100:
00309 case 0x101:
00310 case 0x121:
00311 result->tuner_count = 2;
00312 break;
00313
00314 default:
00315 break;
00316 }
00317 }
00318
00319 return TRUE;
00320 }
00321
00322 static bool_t hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result)
00323 {
00324 unsigned int i;
00325 for (i = 0; i < ds->sock_count; i++) {
00326 struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
00327
00328 if (hdhomerun_discover_recv_internal(ds, dss, result)) {
00329 return TRUE;
00330 }
00331 }
00332
00333 return FALSE;
00334 }
00335
00336 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)
00337 {
00338 int index;
00339 for (index = 0; index < count; index++) {
00340 struct hdhomerun_discover_device_t *entry = &result_list[index];
00341 if (memcmp(lookup, entry, sizeof(struct hdhomerun_discover_device_t)) == 0) {
00342 return entry;
00343 }
00344 }
00345
00346 return NULL;
00347 }
00348
00349 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)
00350 {
00351 hdhomerun_discover_sock_detect(ds);
00352
00353 int count = 0;
00354 int attempt;
00355 for (attempt = 0; attempt < 2; attempt++) {
00356 if (!hdhomerun_discover_send(ds, target_ip, device_type, device_id)) {
00357 return -1;
00358 }
00359
00360 uint64_t timeout = getcurrenttime() + 200;
00361 while (1) {
00362 struct hdhomerun_discover_device_t *result = &result_list[count];
00363 memset(result, 0, sizeof(struct hdhomerun_discover_device_t));
00364
00365 if (!hdhomerun_discover_recv(ds, result)) {
00366 if (getcurrenttime() >= timeout) {
00367 break;
00368 }
00369 msleep_approx(10);
00370 continue;
00371 }
00372
00373
00374 if (device_type != HDHOMERUN_DEVICE_TYPE_WILDCARD) {
00375 if (device_type != result->device_type) {
00376 continue;
00377 }
00378 }
00379 if (device_id != HDHOMERUN_DEVICE_ID_WILDCARD) {
00380 if (device_id != result->device_id) {
00381 continue;
00382 }
00383 }
00384
00385
00386 if (hdhomerun_discover_find_in_list(result_list, count, result)) {
00387 continue;
00388 }
00389
00390
00391 count++;
00392 if (count >= max_count) {
00393 return count;
00394 }
00395 }
00396 }
00397
00398 return count;
00399 }
00400
00401 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)
00402 {
00403 if (hdhomerun_discover_is_ip_multicast(target_ip)) {
00404 return 0;
00405 }
00406
00407 struct hdhomerun_discover_t *ds = hdhomerun_discover_create();
00408 if (!ds) {
00409 return -1;
00410 }
00411
00412 int ret = hdhomerun_discover_find_devices(ds, target_ip, device_type, device_id, result_list, max_count);
00413
00414 hdhomerun_discover_destroy(ds);
00415 return ret;
00416 }
00417
00418 bool_t hdhomerun_discover_validate_device_id(uint32_t device_id)
00419 {
00420 static uint32_t lookup_table[16] = {0xA, 0x5, 0xF, 0x6, 0x7, 0xC, 0x1, 0xB, 0x9, 0x2, 0x8, 0xD, 0x4, 0x3, 0xE, 0x0};
00421
00422 uint32_t checksum = 0;
00423
00424 checksum ^= lookup_table[(device_id >> 28) & 0x0F];
00425 checksum ^= (device_id >> 24) & 0x0F;
00426 checksum ^= lookup_table[(device_id >> 20) & 0x0F];
00427 checksum ^= (device_id >> 16) & 0x0F;
00428 checksum ^= lookup_table[(device_id >> 12) & 0x0F];
00429 checksum ^= (device_id >> 8) & 0x0F;
00430 checksum ^= lookup_table[(device_id >> 4) & 0x0F];
00431 checksum ^= (device_id >> 0) & 0x0F;
00432
00433 return (checksum == 0);
00434 }
00435
00436 bool_t hdhomerun_discover_is_ip_multicast(uint32_t ip_addr)
00437 {
00438 return (ip_addr >= 0xE0000000) && (ip_addr < 0xF0000000);
00439 }