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