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_CONTROL_CONNECT_TIMEOUT 2500
00036 #define HDHOMERUN_CONTROL_SEND_TIMEOUT 2500
00037 #define HDHOMERUN_CONTROL_RECV_TIMEOUT 2500
00038 #define HDHOMERUN_CONTROL_UPGRADE_TIMEOUT 20000
00039
00040 struct hdhomerun_control_sock_t {
00041 uint32_t desired_device_id;
00042 uint32_t desired_device_ip;
00043 uint32_t actual_device_id;
00044 uint32_t actual_device_ip;
00045 hdhomerun_sock_t sock;
00046 struct hdhomerun_debug_t *dbg;
00047 struct hdhomerun_pkt_t tx_pkt;
00048 struct hdhomerun_pkt_t rx_pkt;
00049 };
00050
00051 static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs)
00052 {
00053 if (cs->sock == HDHOMERUN_SOCK_INVALID) {
00054 return;
00055 }
00056
00057 hdhomerun_sock_destroy(cs->sock);
00058 cs->sock = HDHOMERUN_SOCK_INVALID;
00059 }
00060
00061 void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip)
00062 {
00063 hdhomerun_control_close_sock(cs);
00064
00065 cs->desired_device_id = device_id;
00066 cs->desired_device_ip = device_ip;
00067 cs->actual_device_id = 0;
00068 cs->actual_device_ip = 0;
00069 }
00070
00071 struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip, struct hdhomerun_debug_t *dbg)
00072 {
00073 struct hdhomerun_control_sock_t *cs = (struct hdhomerun_control_sock_t *)calloc(1, sizeof(struct hdhomerun_control_sock_t));
00074 if (!cs) {
00075 hdhomerun_debug_printf(dbg, "hdhomerun_control_create: failed to allocate control object\n");
00076 return NULL;
00077 }
00078
00079 cs->dbg = dbg;
00080 cs->sock = HDHOMERUN_SOCK_INVALID;
00081 hdhomerun_control_set_device(cs, device_id, device_ip);
00082
00083 return cs;
00084 }
00085
00086 void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs)
00087 {
00088 hdhomerun_control_close_sock(cs);
00089 free(cs);
00090 }
00091
00092 static bool_t hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs)
00093 {
00094 if (cs->sock != HDHOMERUN_SOCK_INVALID) {
00095 return TRUE;
00096 }
00097
00098 if ((cs->desired_device_id == 0) && (cs->desired_device_ip == 0)) {
00099 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: no device specified\n");
00100 return FALSE;
00101 }
00102 if (hdhomerun_discover_is_ip_multicast(cs->desired_device_ip)) {
00103 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: cannot use multicast ip address for device operations\n");
00104 return FALSE;
00105 }
00106
00107
00108 struct hdhomerun_discover_device_t result;
00109 if (hdhomerun_discover_find_devices_custom(cs->desired_device_ip, HDHOMERUN_DEVICE_TYPE_WILDCARD, cs->desired_device_id, &result, 1) <= 0) {
00110 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: device not found\n");
00111 return FALSE;
00112 }
00113 cs->actual_device_ip = result.ip_addr;
00114 cs->actual_device_id = result.device_id;
00115
00116
00117 cs->sock = hdhomerun_sock_create_tcp();
00118 if (cs->sock == HDHOMERUN_SOCK_INVALID) {
00119 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to create socket (%d)\n", hdhomerun_sock_getlasterror());
00120 return FALSE;
00121 }
00122
00123
00124 if (!hdhomerun_sock_connect(cs->sock, cs->actual_device_ip, HDHOMERUN_CONTROL_TCP_PORT, HDHOMERUN_CONTROL_CONNECT_TIMEOUT)) {
00125 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to connect (%d)\n", hdhomerun_sock_getlasterror());
00126 hdhomerun_control_close_sock(cs);
00127 return FALSE;
00128 }
00129
00130
00131 return TRUE;
00132 }
00133
00134 uint32_t hdhomerun_control_get_device_id(struct hdhomerun_control_sock_t *cs)
00135 {
00136 if (!hdhomerun_control_connect_sock(cs)) {
00137 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_device_id: connect failed\n");
00138 return 0;
00139 }
00140
00141 return cs->actual_device_id;
00142 }
00143
00144 uint32_t hdhomerun_control_get_device_ip(struct hdhomerun_control_sock_t *cs)
00145 {
00146 if (!hdhomerun_control_connect_sock(cs)) {
00147 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_device_ip: connect failed\n");
00148 return 0;
00149 }
00150
00151 return cs->actual_device_ip;
00152 }
00153
00154 uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock_t *cs)
00155 {
00156 return cs->desired_device_id;
00157 }
00158
00159 uint32_t hdhomerun_control_get_device_ip_requested(struct hdhomerun_control_sock_t *cs)
00160 {
00161 return cs->desired_device_ip;
00162 }
00163
00164 uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs)
00165 {
00166 if (!hdhomerun_control_connect_sock(cs)) {
00167 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: connect failed\n");
00168 return 0;
00169 }
00170
00171 uint32_t addr = hdhomerun_sock_getsockname_addr(cs->sock);
00172 if (addr == 0) {
00173 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: getsockname failed (%d)\n", hdhomerun_sock_getlasterror());
00174 return 0;
00175 }
00176
00177 return addr;
00178 }
00179
00180 static bool_t hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt)
00181 {
00182 if (!hdhomerun_sock_send(cs->sock, tx_pkt->start, tx_pkt->end - tx_pkt->start, HDHOMERUN_CONTROL_SEND_TIMEOUT)) {
00183 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_sock: send failed (%d)\n", hdhomerun_sock_getlasterror());
00184 hdhomerun_control_close_sock(cs);
00185 return FALSE;
00186 }
00187
00188 return TRUE;
00189 }
00190
00191 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)
00192 {
00193 uint64_t stop_time = getcurrenttime() + recv_timeout;
00194 hdhomerun_pkt_reset(rx_pkt);
00195
00196 while (1) {
00197 uint64_t current_time = getcurrenttime();
00198 if (current_time >= stop_time) {
00199 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: timeout\n");
00200 hdhomerun_control_close_sock(cs);
00201 return FALSE;
00202 }
00203
00204 size_t length = rx_pkt->limit - rx_pkt->end;
00205 if (!hdhomerun_sock_recv(cs->sock, rx_pkt->end, &length, stop_time - current_time)) {
00206 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: recv failed (%d)\n", hdhomerun_sock_getlasterror());
00207 hdhomerun_control_close_sock(cs);
00208 return FALSE;
00209 }
00210
00211 rx_pkt->end += length;
00212
00213 int ret = hdhomerun_pkt_open_frame(rx_pkt, ptype);
00214 if (ret < 0) {
00215 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_recv_sock: frame error\n");
00216 hdhomerun_control_close_sock(cs);
00217 return FALSE;
00218 }
00219 if (ret > 0) {
00220 return TRUE;
00221 }
00222 }
00223 }
00224
00225 static int hdhomerun_control_send_recv_internal(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt, struct hdhomerun_pkt_t *rx_pkt, uint16_t type, uint64_t recv_timeout)
00226 {
00227 hdhomerun_pkt_seal_frame(tx_pkt, type);
00228
00229 int i;
00230 for (i = 0; i < 2; i++) {
00231 if (cs->sock == HDHOMERUN_SOCK_INVALID) {
00232 if (!hdhomerun_control_connect_sock(cs)) {
00233 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_recv: connect failed\n");
00234 return -1;
00235 }
00236 }
00237
00238 if (!hdhomerun_control_send_sock(cs, tx_pkt)) {
00239 continue;
00240 }
00241 if (!rx_pkt) {
00242 return 1;
00243 }
00244
00245 uint16_t rsp_type;
00246 if (!hdhomerun_control_recv_sock(cs, rx_pkt, &rsp_type, recv_timeout)) {
00247 continue;
00248 }
00249 if (rsp_type != type + 1) {
00250 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_recv: unexpected frame type\n");
00251 hdhomerun_control_close_sock(cs);
00252 continue;
00253 }
00254
00255 return 1;
00256 }
00257
00258 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_recv: failed\n");
00259 return -1;
00260 }
00261
00262 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)
00263 {
00264 return hdhomerun_control_send_recv_internal(cs, tx_pkt, rx_pkt, type, HDHOMERUN_CONTROL_RECV_TIMEOUT);
00265 }
00266
00267 static int hdhomerun_control_get_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, uint32_t lockkey, char **pvalue, char **perror)
00268 {
00269 struct hdhomerun_pkt_t *tx_pkt = &cs->tx_pkt;
00270 struct hdhomerun_pkt_t *rx_pkt = &cs->rx_pkt;
00271
00272
00273 hdhomerun_pkt_reset(tx_pkt);
00274
00275 int name_len = (int)strlen(name) + 1;
00276 if (tx_pkt->end + 3 + name_len > tx_pkt->limit) {
00277 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: request too long\n");
00278 return -1;
00279 }
00280 hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_GETSET_NAME);
00281 hdhomerun_pkt_write_var_length(tx_pkt, name_len);
00282 hdhomerun_pkt_write_mem(tx_pkt, (const void *)name, name_len);
00283
00284 if (value) {
00285 int value_len = (int)strlen(value) + 1;
00286 if (tx_pkt->end + 3 + value_len > tx_pkt->limit) {
00287 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: request too long\n");
00288 return -1;
00289 }
00290 hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_GETSET_VALUE);
00291 hdhomerun_pkt_write_var_length(tx_pkt, value_len);
00292 hdhomerun_pkt_write_mem(tx_pkt, (const void *)value, value_len);
00293 }
00294
00295 if (lockkey != 0) {
00296 if (tx_pkt->end + 6 > tx_pkt->limit) {
00297 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: request too long\n");
00298 return -1;
00299 }
00300 hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_GETSET_LOCKKEY);
00301 hdhomerun_pkt_write_var_length(tx_pkt, 4);
00302 hdhomerun_pkt_write_u32(tx_pkt, lockkey);
00303 }
00304
00305
00306 if (hdhomerun_control_send_recv_internal(cs, tx_pkt, rx_pkt, HDHOMERUN_TYPE_GETSET_REQ, HDHOMERUN_CONTROL_RECV_TIMEOUT) < 0) {
00307 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: send/recv error\n");
00308 return -1;
00309 }
00310
00311
00312 while (1) {
00313 uint8_t tag;
00314 size_t len;
00315 uint8_t *next = hdhomerun_pkt_read_tlv(rx_pkt, &tag, &len);
00316 if (!next) {
00317 break;
00318 }
00319
00320 switch (tag) {
00321 case HDHOMERUN_TAG_GETSET_VALUE:
00322 if (pvalue) {
00323 *pvalue = (char *)rx_pkt->pos;
00324 rx_pkt->pos[len] = 0;
00325 }
00326 if (perror) {
00327 *perror = NULL;
00328 }
00329 return 1;
00330
00331 case HDHOMERUN_TAG_ERROR_MESSAGE:
00332 rx_pkt->pos[len] = 0;
00333 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: %s\n", rx_pkt->pos);
00334
00335 if (pvalue) {
00336 *pvalue = NULL;
00337 }
00338 if (perror) {
00339 *perror = (char *)rx_pkt->pos;
00340 }
00341
00342 return 0;
00343 }
00344
00345 rx_pkt->pos = next;
00346 }
00347
00348 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_set: missing response tags\n");
00349 return -1;
00350 }
00351
00352 int hdhomerun_control_get(struct hdhomerun_control_sock_t *cs, const char *name, char **pvalue, char **perror)
00353 {
00354 return hdhomerun_control_get_set(cs, name, NULL, 0, pvalue, perror);
00355 }
00356
00357 int hdhomerun_control_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror)
00358 {
00359 return hdhomerun_control_get_set(cs, name, value, 0, pvalue, perror);
00360 }
00361
00362 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)
00363 {
00364 return hdhomerun_control_get_set(cs, name, value, lockkey, pvalue, perror);
00365 }
00366
00367 int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade_file)
00368 {
00369 struct hdhomerun_pkt_t *tx_pkt = &cs->tx_pkt;
00370 struct hdhomerun_pkt_t *rx_pkt = &cs->rx_pkt;
00371 uint32_t sequence = 0;
00372
00373
00374 while (1) {
00375 uint8_t data[256];
00376 size_t length = fread(data, 1, 256, upgrade_file);
00377 if (length == 0) {
00378 break;
00379 }
00380
00381 hdhomerun_pkt_reset(tx_pkt);
00382 hdhomerun_pkt_write_u32(tx_pkt, sequence);
00383 hdhomerun_pkt_write_mem(tx_pkt, data, length);
00384
00385 if (hdhomerun_control_send_recv_internal(cs, tx_pkt, NULL, HDHOMERUN_TYPE_UPGRADE_REQ, 0) < 0) {
00386 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_upgrade: send/recv failed\n");
00387 return -1;
00388 }
00389
00390 sequence += (uint32_t)length;
00391 }
00392
00393 if (sequence == 0) {
00394
00395 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_upgrade: zero length file\n");
00396 return 0;
00397 }
00398
00399
00400 hdhomerun_pkt_reset(tx_pkt);
00401 hdhomerun_pkt_write_u32(tx_pkt, 0xFFFFFFFF);
00402
00403 if (hdhomerun_control_send_recv_internal(cs, tx_pkt, rx_pkt, HDHOMERUN_TYPE_UPGRADE_REQ, HDHOMERUN_CONTROL_UPGRADE_TIMEOUT) < 0) {
00404 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_upgrade: send/recv failed\n");
00405 return -1;
00406 }
00407
00408
00409 while (1) {
00410 uint8_t tag;
00411 size_t len;
00412 uint8_t *next = hdhomerun_pkt_read_tlv(rx_pkt, &tag, &len);
00413 if (!next) {
00414 break;
00415 }
00416
00417 switch (tag) {
00418 case HDHOMERUN_TAG_ERROR_MESSAGE:
00419 rx_pkt->pos[len] = 0;
00420 hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_upgrade: %s\n", (char *)rx_pkt->pos);
00421 return 0;
00422
00423 default:
00424 break;
00425 }
00426
00427 rx_pkt->pos = next;
00428 }
00429
00430 return 1;
00431 }