static void xmlrpc_write_map(htsbuf_queue_t *q, htsmsg_t *m) { htsmsg_field_t *f; HTSMSG_FOREACH(f, m) { htsbuf_qprintf(q, "<member><name>%s</name>", f->hmf_name); xmlrpc_write_field(q, f, "", ""); htsbuf_qprintf(q, "</member>\n"); }
static void dump_resource_list(htsbuf_queue_t *out, struct es_resource_list *list) { char buf[512]; es_resource_t *er; LIST_FOREACH(er, list, er_link) { if(er->er_class->erc_info != NULL) { er->er_class->erc_info(er, buf, sizeof(buf)); htsbuf_qprintf(out, "\t%s: %s\n", er->er_class->erc_name, buf); } else { htsbuf_qprintf(out, "\t%s\n", er->er_class->erc_name); } } }
static void diag_html(http_connection_t *hc, htsbuf_queue_t *out) { char p1[1000]; time_t t0; int i; time(&t0); for(i = 0; i <= 5; i++) { struct stat st; snprintf(p1, sizeof(p1), "%s/log/showtime-%d.log", gconf.cache_path,i); if(stat(p1, &st)) continue; char timestr[32]; time_t modtime = t0 - st.st_mtime; if(modtime < 60) snprintf(timestr, sizeof(timestr), "%d seconds", (int)modtime); else if(modtime < 3600) snprintf(timestr, sizeof(timestr), "%d minutes", (int)modtime / 60); else snprintf(timestr, sizeof(timestr), "%d hours", (int)modtime / 3600); htsbuf_qprintf(out, "showtime-%d.log (Last modified %s ago): <a href=\"/showtime/logfile/%d\">View</a> | <a href=\"/showtime/logfile/%d?mode=download\">Download</a>| <a href=\"/showtime/logfile/%d?mode=pastebin\">Pastebin</a><br>", i, timestr, i, i, i); } }
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 }
static int hc_prop(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; rstr_t *r; int rval, i; prop_t *p; const char *action = http_arg_get_req(hc, "action"); if(remain == NULL) return 404; p = prop_from_path(remain); if(p == NULL) return 404; htsbuf_queue_init(&out, 0); switch(method) { case HTTP_CMD_GET: if(action != NULL) { event_t *e = event_create_action_str(action); prop_send_ext_event(p, e); event_release(e); rval = HTTP_STATUS_OK; break; } r = prop_get_string(p, NULL); if(r == NULL) { char **childs = prop_get_name_of_childs(p); if(childs == NULL) { rval = HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE; break; } for(i = 0; childs[i] != NULL; i++) { htsbuf_qprintf(&out, "\t%s\n", childs[i]); } } else { htsbuf_append(&out, rstr_get(r), strlen(rstr_get(r))); htsbuf_append(&out, "\n", 1); rstr_release(r); } rval = http_send_reply(hc, 0, "text/ascii", NULL, NULL, 0, &out); break; default: rval = HTTP_STATUS_METHOD_NOT_ALLOWED; break; } prop_ref_dec(p); return rval; }
static void dump_context(htsbuf_queue_t *out, es_context_t *ec) { hts_mutex_lock(&ec->ec_mutex); htsbuf_qprintf(out, "\n--- %s ------------------------\n", ec->ec_id); htsbuf_qprintf(out, " Loaded from %s\n", ec->ec_path); htsbuf_qprintf(out, " Memory usage, current: %zd bytes, max: %zd\n", ec->ec_mem_active, ec->ec_mem_peak); htsbuf_qprintf(out, " Attached permanent resources:\n"); dump_resource_list(out, &ec->ec_resources_permanent); hts_mutex_unlock(&ec->ec_mutex); }
static void heap_printer(void *opaque, uint32_t addr, uint32_t size, int inuse) { heap_walker_aux_t *aux = opaque; htsbuf_qprintf(aux->out, " 0x%08x + 0x%08x %s\n", addr, size, inuse ? "Used" : "Free"); if(inuse) aux->inuse += size; }
static int hc_done(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; htsbuf_queue_init(&out, 0); htsbuf_qprintf(&out, "OK"); return http_send_reply(hc, 0, "text/ascii", NULL, NULL, 0, &out); }
static int airplay_scrub(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; htsbuf_queue_init(&out, 0); htsbuf_qprintf(&out, "position: 0.123456\r\n" "duration: 50.123456"); return http_send_reply(hc, 0, NULL, NULL, NULL, 0, &out); }
static void xmlrpc_write_field(htsbuf_queue_t *q, htsmsg_field_t *f, const char *pre, const char *post) { switch(f->hmf_type) { case HMF_S64: htsbuf_qprintf(q, "%s<value><int>%"PRId64"</int></value>%s\n", pre, f->hmf_s64, post); break; case HMF_STR: htsbuf_qprintf(q, "%s<value><string>%s</string></value>%s\n", pre, f->hmf_str, post); break; case HMF_LIST: htsbuf_qprintf(q, "%s<value><array><data>", pre); xmlrpc_write_list(q, f->hmf_childs, "", ""); htsbuf_qprintf(q, "</data></array></value>%s\n", post); break; case HMF_MAP: htsbuf_qprintf(q, "%s<value><struct>", pre); xmlrpc_write_map(q, f->hmf_childs); htsbuf_qprintf(q, "</struct></value>%s\n", post); break; } }
static int memstats(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; allsegs_t as = {}; hts_lwmutex_lock(&mutex); tlsf_walk_heap(gpool, list_all_segs_walk, &as); int size = as.count * sizeof(seginfo_t); as.ptr = halloc(size); as.count = 0; tlsf_walk_heap(gpool, list_all_segs_walk, &as); hts_lwmutex_unlock(&mutex); qsort(as.ptr, as.count, sizeof(seginfo_t), seginfo_cmp); htsbuf_queue_init(&out, 0); htsbuf_qprintf(&out, "%d segments ptr=%p\n\n", as.count, as.ptr); int lastsize = -1; int dup = 0; for(int i = 0; i < as.count; i++) { if(as.ptr[i].size == lastsize && i != as.count - 1) { dup++; } else { htsbuf_qprintf(&out, "%s %10d * %d\n", as.ptr[i].used ? "Used" : "Free", as.ptr[i].size, dup + 1); dup = 0; } lastsize = as.ptr[i].size; } hfree(as.ptr, size); return http_send_reply(hc, 0, "text/plain", NULL, NULL, 0, &out); }
void soap_encode_arg(htsbuf_queue_t *xml, htsmsg_field_t *f) { switch(f->hmf_type) { case HMF_S64: htsbuf_qprintf(xml, "<%s>%"PRId64"</%s>", f->hmf_name, f->hmf_s64, f->hmf_name); break; case HMF_STR: if(f->hmf_str[0] == 0) { htsbuf_qprintf(xml, "<%s/>", f->hmf_name); break; } htsbuf_qprintf(xml, "<%s>", f->hmf_name); htsbuf_append_and_escape_xml(xml, f->hmf_str); htsbuf_qprintf(xml, "</%s>", f->hmf_name); break; default: break; } }
static send_event_t * upnp_event_generate_one(upnp_local_service_t *uls, upnp_subscription_t *us) { send_event_t *set; char str[32]; set = malloc(sizeof(send_event_t)); htsbuf_queue_init(&set->out, 0); htsbuf_qprintf(&set->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">"); if(uls->uls_generate_props != NULL) { htsmsg_t *p = uls->uls_generate_props(uls, us->us_myhost, us->us_myport); htsmsg_field_t *f; HTSMSG_FOREACH(f, p) { htsbuf_qprintf(&set->out, "<e:property>"); soap_encode_arg(&set->out, f); htsbuf_qprintf(&set->out, "</e:property>"); }
static int hc_root_old(http_connection_t *hc) { htsbuf_queue_t out; const char *url = http_arg_get_req(hc, "url"); if(url != NULL) { event_dispatch(event_create_openurl(url, NULL, NULL, NULL, NULL, NULL)); return http_redirect(hc, "/"); } htsbuf_queue_init(&out, 0); htsbuf_qprintf(&out, "<html><body>" "<h2>%s</h2><p>Version %s" , gconf.system_name, htsversion_full); htsbuf_qprintf(&out, "<form name=\"input\" method=\"get\">" "Open URL in Showtime: " "<input type=\"text\" name=\"url\" style=\"width:500px\"/>" "<input type=\"submit\" value=\"Open\" />" "</form>"); htsbuf_qprintf(&out, "<h3>Diagnostics</h3>"); diag_html(hc, &out); htsbuf_qprintf(&out, "<p><a href=\"/showtime/translation\">Upload and test new translation (.lang) file</a></p>"); htsbuf_qprintf(&out, "</body></html>"); return http_send_reply(hc, 0, "text/html", NULL, NULL, 0, &out); }
static int dumpstats(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { int i; htsbuf_queue_t out; htsbuf_queue_init(&out, 0); np_context_t **vec = np_get_all_contexts(); for(i = 0; vec[i] != NULL; i++) dump_context(&out, vec[i]); np_context_vec_free(vec); htsbuf_qprintf(&out, "\n"); return http_send_reply(hc, 0, "text/plain; charset=utf-8", NULL, NULL, 0, &out); }
static htsmsg_t * avt_generate_props(upnp_local_service_t *uls, const char *myhost, int myport) { char *event; htsbuf_queue_t xml; char str[256]; const char *s; htsbuf_queue_init(&xml, 0); htsbuf_qprintf(&xml, "<Event xmlns=\"urn:schemas-upnp-org:metadata-1-0/RCS/\">" "<InstanceID val=\"0\">"); upnp_event_encode_str(&xml, "TransportState", current_playstate()); upnp_event_encode_str(&xml, "CurrentMediaCategory", current_mediaCategory()); // PlaybackStorageMedium if(upnp_current_playstatus == NULL) s = "NONE"; else s = "NETWORK"; upnp_event_encode_str(&xml, "PlaybackStorageMedium", s); upnp_event_encode_str(&xml, "CurrentPlayMode", current_playMode()); current_transportActions(str, sizeof(str)); upnp_event_encode_str(&xml, "CurrentTransportActions", str); upnp_event_encode_int(&xml, "NumberOfTracks", upnp_current_total_tracks); upnp_event_encode_int(&xml, "CurrentTrack", upnp_current_track); upnp_event_encode_str(&xml, "AVTransportURI", upnp_current_url ?: ""); upnp_event_encode_int(&xml, "TransportPlaySpeed", 1); // Metadata char *meta = build_didl(myhost, myport); upnp_event_encode_str(&xml, "AVTransportURIMetaData", meta); upnp_event_encode_str(&xml, "CurrentTrackMetaData", meta); free(meta); fmttime(str, sizeof(str), upnp_current_track_duration); upnp_event_encode_str(&xml, "CurrentTrackDuration", str); upnp_event_encode_str(&xml, "CurrentMediaDuration", str); upnp_event_encode_str(&xml, "PossibleRecordQualityModes", NULL); upnp_event_encode_str(&xml, "TransportStatus", "OK"); upnp_event_encode_str(&xml, "DRMState", "UNKNOWN"); upnp_event_encode_str(&xml, "RecordMediumWriteStatus", NULL); upnp_event_encode_str(&xml, "RecordStorageMedium", NULL); upnp_event_encode_str(&xml, "PossibleRecordStorageMedia", NULL); upnp_event_encode_str(&xml, "NextAVTransportURI", ""); upnp_event_encode_str(&xml, "NextAVTransportURIMetaData", NULL); upnp_event_encode_str(&xml, "CurrentRecordQualityMode", NULL); upnp_event_encode_str(&xml, "PossiblePlaybackStorageMedia", "NETWORK"); htsbuf_qprintf(&xml, "</InstanceID></Event>"); event = htsbuf_to_string(&xml); htsmsg_t *r = htsmsg_create_map(); htsmsg_add_str(r, "LastChange", event); free(event); return r; }
static char * build_didl(const char *myhost, int myport) { htsbuf_queue_t hq; htsbuf_queue_init(&hq, 0); htsbuf_qprintf(&hq, "<DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" " "xmlns:dc=\"http://purl.org/dc/elements/1.1/\" " "xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0\" " "xmlns:pv=\"http://www.pv.com/pvns/\" " "xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">" "<item id=\"101\" parentID=\"100\" restricted=\"0\">" "<upnp:class xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">object.item.audioItem.musicTrack</upnp:class>"); if(upnp_current_title) { htsbuf_qprintf(&hq, "<dc:title xmlns:dc=\"http://purl.org/dc/elements/1.1/\">"); htsbuf_append_and_escape_xml(&hq, upnp_current_title); htsbuf_qprintf(&hq, "</dc:title>"); } if(upnp_current_artist) { htsbuf_qprintf(&hq, "<upnp:artist xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">"); htsbuf_append_and_escape_xml(&hq, upnp_current_artist); htsbuf_qprintf(&hq, "</upnp:artist>"); } if(upnp_current_album) { htsbuf_qprintf(&hq, "<upnp:album xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">"); htsbuf_append_and_escape_xml(&hq, upnp_current_album); htsbuf_qprintf(&hq, "</upnp:album>"); } if(upnp_current_album_art) { char url[URL_MAX]; const char *arturl; if(strncmp(upnp_current_album_art, "http://", strlen("http://"))) { snprintf(url, sizeof(url), "http://%s:%d/api/image/%s", myhost, myport, upnp_current_album_art); arturl = url; } else { arturl = upnp_current_album_art; } htsbuf_qprintf(&hq, "<upnp:albumArtURI xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">"); htsbuf_append_and_escape_xml(&hq, arturl); htsbuf_qprintf(&hq, "</upnp:albumArtURI>"); } htsbuf_qprintf(&hq, "</item></DIDL-Lite>"); return htsbuf_to_string(&hq); }
static void fd_printer(void *opaque, int fd, int type) { htsbuf_qprintf(opaque, " fd: %4d type: %d\n", fd, type); }
/** * Root page, we direct the client to different pages depending * on if it is a full blown browser or just some mobile app */ static int page_simple(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *s = http_arg_get(&hc->hc_req_args, "s"); epg_broadcast_t *e; int c, k, i; struct tm a, b, day; dvr_entry_t *de; dvr_query_result_t dqr; const char *rstatus = NULL; epg_query_result_t eqr; const char *lang = http_arg_get(&hc->hc_args, "Accept-Language"); htsbuf_qprintf(hq, "<html>"); htsbuf_qprintf(hq, "<body>"); htsbuf_qprintf(hq, "<form>"); htsbuf_qprintf(hq, "Event: <input type=\"text\" "); if(s != NULL) htsbuf_qprintf(hq, "value=\"%s\" ", s); htsbuf_qprintf(hq, "name=\"s\">"); htsbuf_qprintf(hq, "<input type=\"submit\" value=\"Search\">"); htsbuf_qprintf(hq, "</form><hr>"); pthread_mutex_lock(&global_lock); if(s != NULL) { //Note: force min/max durations for this interface to 0 and INT_MAX seconds respectively epg_query(&eqr, NULL, NULL, NULL, s, lang, 0, INT_MAX); epg_query_sort(&eqr); c = eqr.eqr_entries; if(eqr.eqr_entries == 0) { htsbuf_qprintf(hq, "<b>No matching entries found</b>"); } else { htsbuf_qprintf(hq, "<b>%d entries found", c); if(c > 25) { c = 25; htsbuf_qprintf(hq, ", %d entries shown", c); } htsbuf_qprintf(hq, "</b>"); memset(&day, -1, sizeof(struct tm)); for(k = 0; k < c; k++) { e = eqr.eqr_array[k]; localtime_r(&e->start, &a); localtime_r(&e->stop, &b); if(a.tm_wday != day.tm_wday || a.tm_mday != day.tm_mday || a.tm_mon != day.tm_mon || a.tm_year != day.tm_year) { memcpy(&day, &a, sizeof(struct tm)); htsbuf_qprintf(hq, "<br><i>%s, %d/%d</i><br>", days[day.tm_wday], day.tm_mday, day.tm_mon + 1); } de = dvr_entry_find_by_event(e); rstatus = de != NULL ? val2str(de->de_sched_state, recstatustxt) : NULL; s = epg_broadcast_get_title(e, lang); htsbuf_qprintf(hq, "<a href=\"/eventinfo/%u\">" "%02d:%02d-%02d:%02d %s%s%s</a><br>", e->id, a.tm_hour, a.tm_min, b.tm_hour, b.tm_min, s ?: "", rstatus ? " " : "", rstatus ?: ""); } } htsbuf_qprintf(hq, "<hr>"); epg_query_free(&eqr); }
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); }
static void dump_context(htsbuf_queue_t *out, np_context_t *np) { np_lock(np); htsbuf_qprintf(out, "\n--- %s ------------------------\n", np->np_path); htsbuf_qprintf(out, " Loaded from %s\n", np->np_path); htsbuf_qprintf(out, "\n Heap\n"); heap_walker_aux_t heap = {out}; vmir_walk_heap(np->np_unit, heap_printer, &heap); htsbuf_qprintf(out, " Heap total inuse: %d bytes\n", heap.inuse); htsbuf_qprintf(out, "\n Open descriptors\n"); vmir_walk_fds(np->np_unit, fd_printer, out); const vmir_stats_t *s = vmir_get_stats(np->np_unit); htsbuf_qprintf(out, "\n"); htsbuf_qprintf(out, " Memory usage stats\n"); htsbuf_qprintf(out, " VM code size: %d\n", s->vm_code_size); htsbuf_qprintf(out, " JIT code size: %d\n", s->jit_code_size); htsbuf_qprintf(out, " Data size: %d\n", s->data_size); htsbuf_qprintf(out, " Peak heap size: %d\n", s->peak_heap_size); htsbuf_qprintf(out, " Peak stack usage: %d\n", s->peak_stack_size); htsbuf_qprintf(out, "\n"); htsbuf_qprintf(out, " Code transformation stats\n"); htsbuf_qprintf(out, " Moves killed: %d\n", s->moves_killed); htsbuf_qprintf(out, " Lea+Load combined: %d\n", s->lea_load_combined); htsbuf_qprintf(out, " Lea+Load comb-fail: %d\n", s->lea_load_combined_failed); htsbuf_qprintf(out, " Cmp+Branch combined: %d\n", s->cmp_branch_combine); htsbuf_qprintf(out, " Cmp+Select combined: %d\n", s->cmp_select_combine); htsbuf_qprintf(out, " Mul+Add combined: %d\n", s->mla_combine); htsbuf_qprintf(out, " Load+Cast combined: %d\n", s->load_cast_combine); htsbuf_qprintf(out, "\n"); np_unlock(np); }
static int hc_prop(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; rstr_t *r; int rval, i; prop_t *p = NULL; char *req = (char *)http_arg_get_req(hc, "requests"); char *request; char *saved; if(req == NULL) return 404; htsbuf_queue_init(&out, 0); switch(method) { case HTTP_CMD_POST: for (request = strtok_r(req, ",", &saved); request; request = strtok_r(NULL, ",", &saved)) { p = prop_from_path(request); if (p == NULL) { htsbuf_qprintf(&out, "error:404"); } else { r = prop_get_string(p, NULL); if(r == NULL) { char **childs = prop_get_name_of_childs(p); if(childs == NULL) { htsbuf_qprintf(&out, "error:404"); } else { htsbuf_qprintf(&out, "dir"); for(i = 0; childs[i] != NULL; i++) { htsbuf_qprintf(&out, "%c%s", i ? ',' : ':', childs[i]); } } } else { htsbuf_qprintf(&out, "value:"); htsbuf_append(&out, rstr_get(r), strlen(rstr_get(r))); rstr_release(r); } } htsbuf_append(&out, "\n", 1); } rval = http_send_reply(hc, 0, "text/ascii", NULL, NULL, 0, &out); break; default: rval = HTTP_STATUS_METHOD_NOT_ALLOWED; break; } prop_ref_dec(p); return rval; }