static void satip_discovery_send_msearch(void *aux) { #define MSG "\ M-SEARCH * HTTP/1.1\r\n\ HOST: 239.255.255.250:1900\r\n\ MAN: \"ssdp:discover\"\r\n\ MX: 2\r\n\ ST: urn:ses-com:device:SatIPServer:1\r\n" int attempt = ((intptr_t)aux) % 10; htsbuf_queue_t q; /* UDP is not reliable - send this message three times */ if (attempt < 1 || attempt > 3) return; if (satip_discovery_service == NULL) return; htsbuf_queue_init(&q, 0); htsbuf_append(&q, MSG, sizeof(MSG)-1); htsbuf_qprintf(&q, "USER-AGENT: unix/1.0 UPnP/1.1 TVHeadend/%s\r\n", tvheadend_version); htsbuf_append(&q, "\r\n", 2); upnp_send(&q, NULL, 0); htsbuf_queue_flush(&q); gtimer_arm_ms(&satip_discovery_msearch_timer, satip_discovery_send_msearch, (void *)(intptr_t)(attempt + 1), attempt * 11); #undef MSG }
void tcp_close(tcp_stream_t *ts) { if(ts->ts_ssl != NULL) { SSL_shutdown(ts->ts_ssl); SSL_free(ts->ts_ssl); } htsbuf_queue_flush(&ts->ts_spill); htsbuf_queue_flush(&ts->ts_sendq); if(ts->ts_fd != -1) { int r = close(ts->ts_fd); if(r) printf("Close failed!\n"); } free(ts); }
void hts_settings_save(htsmsg_t *record, const char *pathfmt, ...) { char path[PATH_MAX]; char tmppath[PATH_MAX]; int fd; va_list ap; htsbuf_queue_t hq; htsbuf_data_t *hd; int ok, r, pack; if(settingspath == NULL) return; /* Clean the path */ va_start(ap, pathfmt); _hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath); va_end(ap); /* Create directories */ if (hts_settings_makedirs(path)) return; tvhdebug("settings", "saving to %s", path); /* Create tmp file */ snprintf(tmppath, sizeof(tmppath), "%s.tmp", path); if((fd = tvh_open(tmppath, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { tvhlog(LOG_ALERT, "settings", "Unable to create \"%s\" - %s", tmppath, strerror(errno)); return; } /* Store data */ #if ENABLE_ZLIB pack = strstr(path, "/muxes/") != NULL && /* ugly, redesign API */ strstr(path, "/networks/") != NULL && strstr(path, "/input/") != NULL; #else pack = 0; #endif ok = 1; if (!pack) { htsbuf_queue_init(&hq, 0); htsmsg_json_serialize(record, &hq, 1); TAILQ_FOREACH(hd, &hq.hq_q, hd_link) if(tvh_write(fd, hd->hd_data + hd->hd_data_off, hd->hd_data_len)) { tvhlog(LOG_ALERT, "settings", "Failed to write file \"%s\" - %s", tmppath, strerror(errno)); ok = 0; break; } htsbuf_queue_flush(&hq); } else {
void hts_settings_save(htsmsg_t *record, const char *pathfmt, ...) { char path[256]; char tmppath[256]; int fd; va_list ap; htsbuf_queue_t hq; htsbuf_data_t *hd; int ok; if(settingspath == NULL) return; /* Clean the path */ va_start(ap, pathfmt); _hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath); va_end(ap); /* Create directories */ if (hts_settings_makedirs(path)) return; tvhdebug("settings", "saving to %s", path); /* Create tmp file */ snprintf(tmppath, sizeof(tmppath), "%s.tmp", path); if((fd = tvh_open(tmppath, O_CREAT | O_TRUNC | O_RDWR, 0700)) < 0) { tvhlog(LOG_ALERT, "settings", "Unable to create \"%s\" - %s", tmppath, strerror(errno)); return; } /* Store data */ ok = 1; htsbuf_queue_init(&hq, 0); htsmsg_json_serialize(record, &hq, 1); TAILQ_FOREACH(hd, &hq.hq_q, hd_link) if(tvh_write(fd, hd->hd_data + hd->hd_data_off, hd->hd_data_len)) { tvhlog(LOG_ALERT, "settings", "Failed to write file \"%s\" - %s", tmppath, strerror(errno)); ok = 0; break; } close(fd); htsbuf_queue_flush(&hq); /* Move */ if(ok) { rename(tmppath, path); /* Delete tmp */ } else unlink(tmppath); }
void tcp_close(tcpcon_t *tc) { #if ENABLE_POLARSSL if(tc->ssl != NULL) { ssl_close_notify(tc->ssl); ssl_free(tc->ssl); free(tc->ssl); free(tc->ssn); free(tc->hs); } #endif htsbuf_queue_flush(&tc->spill); netClose(tc->fd); free(tc); }
void upnp_server_done(void) { upnp_data_t *data; upnp_service_t *us; atomic_set(&upnp_running, 0); tvh_thread_kill(upnp_tid, SIGTERM); pthread_join(upnp_tid, NULL); while ((us = TAILQ_FIRST(&upnp_services)) != NULL) upnp_service_destroy(us); while ((data = TAILQ_FIRST(&upnp_data_write)) != NULL) { TAILQ_REMOVE(&upnp_data_write, data, data_link); htsbuf_queue_flush(&data->queue); free(data); } }
static const void *description_get(wizard_page_t *page, const char **doc) { htsbuf_queue_t q; if (!page->desc) { htsbuf_queue_init(&q, 0); for (; *doc; doc++) { if (*doc[0] == '\xff') { htsbuf_append_str(&q, tvh_gettext_lang(config.language_ui, *doc + 1)); } else { htsbuf_append_str(&q, *doc); } } page->desc = htsbuf_to_string(&q); htsbuf_queue_flush(&q); } return &page->desc; }
void tcp_close(tcpcon_t *tc) { #if ENABLE_OPENSSL if(tc->ssl != NULL) { SSL_shutdown(tc->ssl); SSL_free(tc->ssl); } #endif #if ENABLE_POLARSSL if(tc->ssl != NULL) { ssl_close_notify(tc->ssl); ssl_free(tc->ssl); free(tc->ssl); free(tc->ssn); free(tc->hs); } #endif close(tc->fd); htsbuf_queue_flush(&tc->spill); free(tc); }
static void * lirc_thread(void *aux) { char buf[200]; uint64_t ircode; uint32_t repeat; char keyname[100]; int i, r, fd, len, n; htsbuf_queue_t q; struct pollfd fds; event_t *e; fd = lirc_fd; htsbuf_queue_init(&q, 0); fds.fd = fd; fds.events = POLLIN; while(1) { r = poll(&fds, 1, -1); if(r > 0) { if((r = read(fd, buf, sizeof(buf))) < 1) { TRACE(TRACE_ERROR, "lircd", "Read error: %s", strerror(errno)); break; } htsbuf_append(&q, buf, r); } while((len = htsbuf_find(&q, 0xa)) != -1) { if(len >= sizeof(buf) - 1) { TRACE(TRACE_ERROR, "lircd", "Command buffer size exceeded"); goto out; } htsbuf_read(&q, buf, len); buf[len] = 0; while(len > 0 && buf[len - 1] < 32) buf[--len] = 0; htsbuf_drop(&q, 1); /* Drop the \n */ n = sscanf(buf, "%"PRIx64" %x %s", &ircode, &repeat, keyname); if(n != 3) { TRACE(TRACE_INFO, "lircd", "Invalid LIRC input: \"%s\"", buf); continue; } if(keyname[0] && keyname[1] == 0) { /* ASCII input */ e = event_create_int(EVENT_UNICODE, keyname[0]); } else { e = NULL; for(i = 0; i < sizeof(lircmap) / sizeof(lircmap[0]); i++) { if(!strcasecmp(keyname, lircmap[i].name)) { action_type_t av[3] = { lircmap[i].action1, lircmap[i].action2, }; if(av[1] != ACTION_NONE) e = event_create_action_multi(av, 2); else e = event_create_action_multi(av, 1); break; } } } if(e == NULL) { snprintf(buf, sizeof(buf), "IR+%s", keyname); e = event_create_str(EVENT_KEYDESC, buf); } event_to_ui(e); } } out: close(fd); htsbuf_queue_flush(&q); return NULL; }
/* * Discovery thread */ static void * upnp_thread( void *aux ) { char *bindaddr = aux; tvhpoll_t *poll = tvhpoll_create(2); tvhpoll_event_t ev[2]; upnp_data_t *data; udp_connection_t *multicast = NULL, *unicast = NULL; udp_connection_t *conn; unsigned char buf[16384]; upnp_service_t *us; struct sockaddr_storage ip; socklen_t iplen; size_t size; int r, delay_ms; multicast = udp_bind(LS_UPNP, "upnp_thread_multicast", "239.255.255.250", 1900, NULL, NULL, 32*1024, 32*1024); if (multicast == NULL || multicast == UDP_FATAL_ERROR) goto error; unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, NULL, NULL, 32*1024, 32*1024); if (unicast == NULL || unicast == UDP_FATAL_ERROR) goto error; memset(&ev, 0, sizeof(ev)); ev[0].fd = multicast->fd; ev[0].events = TVHPOLL_IN; ev[0].ptr = multicast; ev[1].fd = unicast->fd; ev[1].events = TVHPOLL_IN; ev[1].ptr = unicast; tvhpoll_add(poll, ev, 2); delay_ms = 0; while (atomic_get(&upnp_running) && multicast->fd >= 0) { r = tvhpoll_wait(poll, ev, 2, delay_ms ?: 1000); if (r == 0) /* timeout */ delay_ms = 0; while (r-- > 0) { if ((ev[r].events & TVHPOLL_IN) != 0) { conn = ev[r].ptr; iplen = sizeof(ip); size = recvfrom(conn->fd, buf, sizeof(buf), 0, (struct sockaddr *)&ip, &iplen); if (size > 0 && tvhtrace_enabled()) { char tbuf[256]; inet_ntop(ip.ss_family, IP_IN_ADDR(ip), tbuf, sizeof(tbuf)); tvhtrace(LS_UPNP, "%s - received data from %s:%hu [size=%zi]", conn == multicast ? "multicast" : "unicast", tbuf, (unsigned short) ntohs(IP_PORT(ip)), size); tvhlog_hexdump(LS_UPNP, buf, size); } /* TODO: a filter */ TAILQ_FOREACH(us, &upnp_services, us_link) us->us_received(buf, size, conn, &ip); } } while (delay_ms == 0) { tvh_mutex_lock(&upnp_lock); data = TAILQ_FIRST(&upnp_data_write); if (data) { delay_ms = data->delay_ms; data->delay_ms = 0; if (!delay_ms) { TAILQ_REMOVE(&upnp_data_write, data, data_link); } else { data = NULL; } } tvh_mutex_unlock(&upnp_lock); if (data == NULL) break; upnp_dump_data(data); udp_write_queue(data->from_multicast ? multicast : unicast, &data->queue, &data->storage); htsbuf_queue_flush(&data->queue); free(data); delay_ms = 0; } } /* flush the write queue (byebye messages) */ while (1) { tvh_mutex_lock(&upnp_lock); data = TAILQ_FIRST(&upnp_data_write); if (data) TAILQ_REMOVE(&upnp_data_write, data, data_link); tvh_mutex_unlock(&upnp_lock); if (data == NULL) break; tvh_safe_usleep((long)data->delay_ms * 1000); upnp_dump_data(data); udp_write_queue(unicast, &data->queue, &data->storage); htsbuf_queue_flush(&data->queue); free(data); } error: atomic_set(&upnp_running, 0); tvhpoll_destroy(poll); udp_close(unicast); udp_close(multicast); return NULL; }
int soap_exec(const char *uri, const char *service, int version, const char *method, htsmsg_t *in, htsmsg_t **outp, char *errbuf, size_t errlen) { int r; htsmsg_t *out; htsbuf_queue_t post; buf_t *result; struct http_header_list hdrs = {0}; char tmp[100]; htsbuf_queue_init(&post, 0); htsbuf_qprintf(&post, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<s:Envelope s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" "<s:Body><ns0:%s xmlns:ns0=\"urn:schemas-upnp-org:service:%s:%d\">", method, service, version); soap_encode_args(&post, in); htsbuf_qprintf(&post, "</ns0:%s></s:Body></s:Envelope>", method); snprintf(tmp, sizeof(tmp),"\"urn:schemas-upnp-org:service:%s:%d#%s\"", service, version, method); http_header_add(&hdrs, "SOAPACTION", tmp, 0); r = http_request(uri, NULL, &result, errbuf, errlen, &post, "text/xml; charset=\"utf-8\"", 0, NULL, &hdrs, NULL, NULL, NULL); http_headers_free(&hdrs); htsbuf_queue_flush(&post); if(r) return -1; out = htsmsg_xml_deserialize_buf2(result, errbuf, errlen); if(out == NULL) return -1; snprintf(tmp, sizeof(tmp), "urn:schemas-upnp-org:service:%s:%d%sResponse", service, version, method); htsmsg_t *outargs = htsmsg_get_map_multi(out, "tags", "http://schemas.xmlsoap.org/soap/envelope/Envelope", "tags", "http://schemas.xmlsoap.org/soap/envelope/Body", "tags", tmp, "tags", NULL); if(outargs != NULL) { htsmsg_field_t *f; htsmsg_t *out = htsmsg_create_map(); // Convert args from XML style to more compact style HTSMSG_FOREACH(f, outargs) { htsmsg_t *a; const char *s; if((a = htsmsg_get_map_by_field(f)) == NULL) continue; if((s = htsmsg_get_str(a, "cdata")) != NULL) htsmsg_add_str(out, f->hmf_name, s); }
/* * Discovery thread */ static void * upnp_thread( void *aux ) { char *bindaddr = aux; tvhpoll_t *poll = tvhpoll_create(2); tvhpoll_event_t ev[2]; upnp_data_t *data; udp_connection_t *multicast = NULL, *unicast = NULL; udp_connection_t *conn; unsigned char buf[16384]; upnp_service_t *us; struct sockaddr_storage ip; socklen_t iplen; size_t size; int r; multicast = udp_bind("upnp", "upnp_thread_multicast", "239.255.255.250", 1900, NULL, 32*1024); if (multicast == NULL || multicast == UDP_FATAL_ERROR) goto error; unicast = udp_bind("upnp", "upnp_thread_unicast", bindaddr, 0, NULL, 32*1024); if (unicast == NULL || unicast == UDP_FATAL_ERROR) goto error; memset(&ev, 0, sizeof(ev)); ev[0].fd = multicast->fd; ev[0].events = TVHPOLL_IN; ev[0].data.ptr = multicast; ev[1].fd = unicast->fd; ev[1].events = TVHPOLL_IN; ev[1].data.ptr = unicast; tvhpoll_add(poll, ev, 2); while (upnp_running && multicast->fd >= 0) { r = tvhpoll_wait(poll, ev, 2, 1000); while (r-- > 0) { if ((ev[r].events & TVHPOLL_IN) != 0) { conn = ev[r].data.ptr; iplen = sizeof(ip); size = recvfrom(conn->fd, buf, sizeof(buf), 0, (struct sockaddr *)&ip, &iplen); #if ENABLE_TRACE if (size > 0) { char tbuf[256]; inet_ntop(ip.ss_family, IP_IN_ADDR(ip), tbuf, sizeof(tbuf)); tvhtrace("upnp", "%s - received data from %s:%hu [size=%zi]", conn == multicast ? "multicast" : "unicast", tbuf, (unsigned short) IP_PORT(ip), size); tvhlog_hexdump("upnp", buf, size); } #endif /* TODO: a filter */ TAILQ_FOREACH(us, &upnp_services, us_link) us->us_received(buf, size, conn, &ip); } } while (1) { pthread_mutex_lock(&upnp_lock); data = TAILQ_FIRST(&upnp_data_write); if (data) TAILQ_REMOVE(&upnp_data_write, data, data_link); pthread_mutex_unlock(&upnp_lock); if (data == NULL) break; udp_write_queue(unicast, &data->queue, &data->storage); htsbuf_queue_flush(&data->queue); free(data); } } error: upnp_running = 0; tvhpoll_destroy(poll); udp_close(unicast); udp_close(multicast); return NULL; }