tcp_stream_t * tcp_stream_create_from_fd(int fd) { tcp_stream_t *ts = calloc(1, sizeof(tcp_stream_t)); ts->ts_fd = fd; htsbuf_queue_init(&ts->ts_spill, INT32_MAX); htsbuf_queue_init(&ts->ts_sendq, INT32_MAX); ts->ts_write = os_write; ts->ts_read = os_read; return ts; }
static void screenshot_response_task(void *task) { response_t *r = task; hts_mutex_lock(&screenshot_mutex); if(screenshot_connection == NULL) { hts_mutex_unlock(&screenshot_mutex); } else { http_connection_t *hc = screenshot_connection; screenshot_connection = NULL; hts_mutex_unlock(&screenshot_mutex); if(r->url != NULL) { http_redirect(hc, r->url); } else { const char *msg = r->errmsg; if(msg == NULL) msg = "Error not specified"; htsbuf_queue_t out; htsbuf_queue_init(&out, 0); htsbuf_append(&out, msg, strlen(msg)); htsbuf_append_byte(&out, '\n'); http_send_reply(hc, 500, "text/plain", NULL, NULL, 0, &out); } } free(r->url); free(r->errmsg); free(r); }
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 }
JSBool js_json_encode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *o; htsbuf_queue_t out; char *r; size_t len; if(!JS_ConvertArguments(cx, argc, argv, "o", &o)) return JS_FALSE; if(o == NULL) { JS_ReportError(cx, "Not an object"); return JS_FALSE; } htsbuf_queue_init(&out, 0); json_encode_from_object(cx, o, &out); len = out.hq_size; r = malloc(out.hq_size+1); r[len] = 0; htsbuf_read(&out, r, len); *rval = STRING_TO_JSVAL(JS_NewString(cx, r, len)); return JS_TRUE; }
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; }
tcpcon_t * tcp_from_fd(int fd) { tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = fd; htsbuf_queue_init(&tc->spill, 0); tc->read = tcp_read; tc->write = tcp_write; return tc; }
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); }
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); }
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); }
tcpcon_t * tcp_connect_arch(const net_addr_t *na, char *errbuf, size_t errlen, int timeout, cancellable_t *c, int dbg) { PP_Resource sock = ppb_tcpsocket->Create(g_Instance); PP_Resource addr; struct PP_NetAddress_IPv4 ipv4_addr = {}; struct PP_NetAddress_IPv6 ipv6_addr = {}; switch(na->na_family) { case 4: memcpy(ipv4_addr.addr, na->na_addr, 4); wr16_be((uint8_t *)&ipv4_addr.port, na->na_port); addr = ppb_netaddress->CreateFromIPv4Address(g_Instance, &ipv4_addr); break; case 6: memcpy(ipv6_addr.addr, na->na_addr, 16); wr16_be((uint8_t *)&ipv6_addr.port, na->na_port); addr = ppb_netaddress->CreateFromIPv6Address(g_Instance, &ipv6_addr); break; default: abort(); } if(dbg) { // debug struct PP_Var remote = ppb_netaddress->DescribeAsString(addr, 1); uint32_t len; const char *s = ppb_var->VarToUtf8(remote, &len); TRACE(TRACE_DEBUG, "TCP", "Connecting to %d %.*s", len, len, s); ppb_var->Release(remote); } int r = ppb_tcpsocket->Connect(sock, addr, PP_BlockUntilComplete()); ppb_core->ReleaseResource(addr); if(r) { snprintf(errbuf, errlen, "Unable to connect -- %s", pepper_errmsg(r)); ppb_core->ReleaseResource(sock); return NULL; } tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = sock; htsbuf_queue_init(&tc->spill, 0); tc->read = tcp_read; tc->write = tcp_write; return tc; }
static int hc_image(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; pixmap_t *pm; char errbuf[200]; const char *content; image_meta_t im = {0}; im.im_no_decoding = 1; rstr_t *url = rstr_alloc(remain); pm = backend_imageloader(url, &im, NULL, errbuf, sizeof(errbuf), NULL, NULL, NULL); rstr_release(url); if(pm == NULL) return http_error(hc, 404, "Unable to load image %s : %s", remain, errbuf); if(!pixmap_is_coded(pm)) { pixmap_release(pm); return http_error(hc, 404, "Unable to load image %s : Original data not available", remain); } htsbuf_queue_init(&out, 0); htsbuf_append(&out, pm->pm_data, pm->pm_size); switch(pm->pm_type) { case PIXMAP_JPEG: content = "image/jpeg"; break; case PIXMAP_PNG: content = "image/png"; break; case PIXMAP_GIF: content = "image/gif"; break; default: content = "image"; break; } pixmap_release(pm); return http_send_reply(hc, 0, content, NULL, NULL, 0, &out); }
static int hc_open(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { 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, "/showtime/open"); } htsbuf_queue_init(&out, 0); htsbuf_append(&out, openpage, strlen(openpage)); return http_send_reply(hc, 0, "text/html", NULL, NULL, 0, &out); }
void upnp_send( htsbuf_queue_t *q, struct sockaddr_storage *storage ) { upnp_data_t *data; if (!upnp_running) return; data = calloc(1, sizeof(upnp_data_t)); htsbuf_queue_init(&data->queue, 0); htsbuf_appendq(&data->queue, q); if (storage == NULL) data->storage = upnp_ipv4_multicast; else data->storage = *storage; pthread_mutex_lock(&upnp_lock); TAILQ_INSERT_TAIL(&upnp_data_write, data, data_link); pthread_mutex_unlock(&upnp_lock); }
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; }
static void * send_report(void *aux) { htsmsg_t *m = aux; htsbuf_queue_t hq; htsbuf_queue_init(&hq, 0); htsmsg_add_msg(m, "plugins", plugins_get_installed_list()); htsmsg_json_serialize(m, &hq, 0); http_req("https://movian.tv/movian/status/v1/usage", HTTP_POSTDATA(&hq, "application/json"), NULL); htsmsg_release(m); return NULL; }
void upnp_send( htsbuf_queue_t *q, struct sockaddr_storage *storage, int delay_ms, int from_multicast ) { upnp_data_t *data; if (!atomic_get(&upnp_running)) return; data = calloc(1, sizeof(upnp_data_t)); htsbuf_queue_init(&data->queue, 0); htsbuf_appendq(&data->queue, q); if (storage == NULL) data->storage = upnp_ipv4_multicast; else data->storage = *storage; data->delay_ms = delay_ms; data->from_multicast = from_multicast; tvh_mutex_lock(&upnp_lock); TAILQ_INSERT_TAIL(&upnp_data_write, data, data_link); tvh_mutex_unlock(&upnp_lock); }
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 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); }
JSBool js_cache_put(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char stash[256]; const char *key,*lstash; char *value; uint32_t len, maxage; JSObject *o; htsbuf_queue_t out; js_plugin_t *jsp = JS_GetPrivate(cx, obj); if (!JS_ConvertArguments(cx, argc, argv, "ssou", &lstash, &key, &o, &maxage)) return JS_FALSE; if (o == NULL) { JS_ReportError(cx, "Not an object"); return JS_FALSE; } // json encode object htsbuf_queue_init(&out, 0); if (json_encode_from_object(cx, o, &out) != 0) { JS_ReportError(cx, "Not an JSON object"); return JS_FALSE; } len = out.hq_size; value = JS_malloc(cx,len + 1); value[len] = '\0'; htsbuf_read(&out, value, len); // put json encoded object onto cache snprintf(stash, sizeof(stash), "plugin/%s/%s", jsp->jsp_id, lstash); blobcache_put(key, stash, value, len, maxage, NULL, 0); return JS_TRUE; }
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); }
tcpcon_t * tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout, int ssl) { struct hostent *hp; char *tmphstbuf; int fd, val, r, err, herr; const char *errtxt; #if !defined(__APPLE__) struct hostent hostbuf; size_t hstbuflen; int res; #endif struct sockaddr_in6 in6; struct sockaddr_in in; socklen_t errlen = sizeof(int); if(!strcmp(hostname, "localhost")) { if((fd = getstreamsocket(AF_INET, errbuf, errbufsize)) == -1) return NULL; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); } else { #if defined(__APPLE__) herr = 0; tmphstbuf = NULL; /* free NULL is a nop */ /* TODO: AF_INET6 */ hp = gethostbyname(hostname); if(hp == NULL) herr = h_errno; #else hstbuflen = 1024; tmphstbuf = malloc(hstbuflen); while((res = gethostbyname_r(hostname, &hostbuf, tmphstbuf, hstbuflen, &hp, &herr)) == ERANGE) { hstbuflen *= 2; tmphstbuf = realloc(tmphstbuf, hstbuflen); } #endif if(herr != 0) { switch(herr) { case HOST_NOT_FOUND: errtxt = "Unknown host"; break; case NO_ADDRESS: errtxt = "The requested name is valid but does not have an IP address"; break; case NO_RECOVERY: errtxt = "A non-recoverable name server error occurred"; break; case TRY_AGAIN: errtxt = "A temporary error occurred on an authoritative name server"; break; default: errtxt = "Unknown error"; break; } snprintf(errbuf, errbufsize, "%s", errtxt); free(tmphstbuf); return NULL; } else if(hp == NULL) { snprintf(errbuf, errbufsize, "Resolver internal error"); free(tmphstbuf); return NULL; } if((fd = getstreamsocket(hp->h_addrtype, errbuf, errbufsize)) == -1) { free(tmphstbuf); return NULL; } switch(hp->h_addrtype) { case AF_INET: memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); memcpy(&in.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); break; case AF_INET6: memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; in6.sin6_port = htons(port); memcpy(&in6.sin6_addr, hp->h_addr_list[0], sizeof(struct in6_addr)); r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in6)); break; default: snprintf(errbuf, errbufsize, "Invalid protocol family"); free(tmphstbuf); return NULL; } free(tmphstbuf); } if(r == -1) { if(errno == EINPROGRESS) { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT; pfd.revents = 0; r = poll(&pfd, 1, timeout); if(r == 0) { /* Timeout */ snprintf(errbuf, errbufsize, "Connection attempt timed out"); close(fd); return NULL; } if(r == -1) { snprintf(errbuf, errbufsize, "poll() error: %s", strerror(errno)); close(fd); return NULL; } getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen); } else { err = errno; } } else { err = 0; } if(err != 0) { snprintf(errbuf, errbufsize, "%s", strerror(err)); close(fd); return NULL; } fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = fd; htsbuf_queue_init(&tc->spill, 0); if(ssl) { #if ENABLE_OPENSSL if(showtime_ssl_ctx != NULL) { char errmsg[120]; if((tc->ssl = SSL_new(showtime_ssl_ctx)) == NULL) { ERR_error_string(ERR_get_error(), errmsg); snprintf(errbuf, errlen, "SSL: %s", errmsg); tcp_close(tc); return NULL; } if(SSL_set_fd(tc->ssl, tc->fd) == 0) { ERR_error_string(ERR_get_error(), errmsg); snprintf(errbuf, errlen, "SSL fd: %s", errmsg); tcp_close(tc); return NULL; } if(SSL_connect(tc->ssl) <= 0) { ERR_error_string(ERR_get_error(), errmsg); snprintf(errbuf, errlen, "SSL connect: %s", errmsg); tcp_close(tc); return NULL; } SSL_set_mode(tc->ssl, SSL_MODE_AUTO_RETRY); tc->read = ssl_read; tc->write = ssl_write; } else #elif ENABLE_POLARSSL if(1) { tc->ssl = malloc(sizeof(ssl_context)); if(ssl_init(tc->ssl)) { snprintf(errbuf, errlen, "SSL failed to initialize"); close(fd); free(tc->ssl); free(tc); return NULL; } tc->ssn = malloc(sizeof(ssl_session)); tc->hs = malloc(sizeof(havege_state)); havege_init(tc->hs); memset(tc->ssn, 0, sizeof(ssl_session)); ssl_set_endpoint(tc->ssl, SSL_IS_CLIENT ); ssl_set_authmode(tc->ssl, SSL_VERIFY_NONE ); ssl_set_rng(tc->ssl, havege_rand, tc->hs ); ssl_set_bio(tc->ssl, net_recv, &tc->fd, net_send, &tc->fd); ssl_set_ciphers(tc->ssl, ssl_default_ciphers ); ssl_set_session(tc->ssl, 1, 600, tc->ssn ); tc->read = polarssl_read; tc->write = polarssl_write; } else #endif { snprintf(errbuf, errlen, "SSL not supported"); tcp_close(tc); return NULL; } } else { tc->read = tcp_read; tc->write = tcp_write; } return tc; }
static int hc_image(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; image_t *img; char errbuf[200]; const char *content; image_meta_t im = {0}; im.im_no_decoding = 1; rstr_t *url; const char *u = http_arg_get_req(hc, "url"); if(u != NULL) { url = rstr_alloc(u); url_deescape(rstr_data(url)); } else { if(remain == NULL) { return 404; } url = rstr_alloc(remain); } img = backend_imageloader(url, &im, NULL, errbuf, sizeof(errbuf), NULL, NULL); rstr_release(url); if(img == NULL) return http_error(hc, 404, "Unable to load image %s : %s", remain, errbuf); const image_component_t *ic = image_find_component(img, IMAGE_CODED); if(ic == NULL) { image_release(img); return http_error(hc, 404, "Unable to load image %s : Original data not available", remain); } const image_component_coded_t *icc = &ic->coded; htsbuf_queue_init(&out, 0); htsbuf_append(&out, buf_cstr(icc->icc_buf), buf_len(icc->icc_buf)); switch(icc->icc_type) { case IMAGE_JPEG: content = "image/jpeg"; break; case IMAGE_PNG: content = "image/png"; break; case IMAGE_GIF: content = "image/gif"; break; default: content = "image"; break; } image_release(img); return http_send_reply(hc, 0, content, NULL, NULL, 0, &out); }
static void screenshot_process(void *task) { pixmap_t *pm = task; if(pm == NULL) { screenshot_response(NULL, "Screenshot not supported on this platform"); return; } TRACE(TRACE_DEBUG, "Screenshot", "Processing image %d x %d", pm->pm_width, pm->pm_height); int codecid = AV_CODEC_ID_PNG; if(screenshot_connection) codecid = AV_CODEC_ID_MJPEG; buf_t *b = screenshot_compress(pm, codecid); pixmap_release(pm); if(b == NULL) { screenshot_response(NULL, "Unable to compress image"); return; } if(!screenshot_connection) { char path[512]; char errbuf[512]; snprintf(path, sizeof(path), "%s/screenshot.png", gconf.cache_path); fa_handle_t *fa = fa_open_ex(path, errbuf, sizeof(errbuf), FA_WRITE, NULL); if(fa == NULL) { TRACE(TRACE_ERROR, "SCREENSHOT", "Unable to open %s -- %s", path, errbuf); buf_release(b); return; } fa_write(fa, buf_data(b), buf_len(b)); fa_close(fa); TRACE(TRACE_INFO, "SCREENSHOT", "Written to %s", path); buf_release(b); return; } buf_t *result = NULL; htsbuf_queue_t hq; htsbuf_queue_init(&hq, 0); htsbuf_append(&hq, "image=", 6); htsbuf_append_and_escape_url_len(&hq, buf_cstr(b), buf_len(b)); char errbuf[256]; int ret = http_req("https://api.imgur.com/3/upload", HTTP_FLAGS(FA_CONTENT_ON_ERROR), HTTP_REQUEST_HEADER("Authorization", "Client-ID 7c79b311d4797ed"), HTTP_RESULT_PTR(&result), HTTP_POSTDATA(&hq, "application/x-www-form-urlencoded"), HTTP_ERRBUF(errbuf, sizeof(errbuf)), NULL); if(ret) { screenshot_response(NULL, errbuf); } else { htsmsg_t *response = htsmsg_json_deserialize(buf_cstr(result)); if(response == NULL) { screenshot_response(NULL, "Unable to parse imgur response"); } else { if(htsmsg_get_u32_or_default(response, "success", 0)) { const char *url = htsmsg_get_str_multi(response, "data", "link", NULL); screenshot_response(url, "No link in imgur response"); } else { const char *msg = htsmsg_get_str_multi(response, "data", "error", NULL); if(msg == NULL) { screenshot_response(NULL, "Unkown imgur error"); } else { snprintf(errbuf, sizeof(errbuf), "Imgur error: %s", msg); screenshot_response(NULL, errbuf); } } htsmsg_release(response); } buf_release(result); } buf_release(b); }
tcpcon_t * tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout, int ssl) { struct net_hostent *hp; char *tmphstbuf; int fd, r, err, herr, optval; const char *errtxt; struct sockaddr_in in; socklen_t errlen = sizeof(int); if(!strcmp(hostname, "localhost")) { if((fd = getstreamsocket(AF_INET, errbuf, errbufsize)) == -1) return NULL; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = netConnect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); } else { herr = 0; tmphstbuf = NULL; /* free NULL is a nop */ hp = netGetHostByName(hostname); if(hp == NULL) herr = h_errno; if(herr != 0) { switch(herr) { case HOST_NOT_FOUND: errtxt = "Unknown host"; break; case NO_ADDRESS: errtxt = "The requested name is valid but does not have an IP address"; break; case NO_RECOVERY: errtxt = "A non-recoverable name server error occurred"; break; case TRY_AGAIN: errtxt = "A temporary error occurred on an authoritative name server"; break; default: errtxt = "Unknown error"; break; } snprintf(errbuf, errbufsize, "%s", errtxt); free(tmphstbuf); return NULL; } else if(hp == NULL) { snprintf(errbuf, errbufsize, "Resolver internal error"); free(tmphstbuf); return NULL; } if((fd = getstreamsocket(hp->h_addrtype, errbuf, errbufsize)) == -1) { free(tmphstbuf); return NULL; } switch(hp->h_addrtype) { case AF_INET: memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); lv2_void* netaddrlist = (lv2_void*)(u64)hp->h_addr_list; memcpy(&in.sin_addr, (char*)(u64)netaddrlist[0], sizeof(struct in_addr)); r = netConnect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); break; default: snprintf(errbuf, errbufsize, "Invalid protocol family"); free(tmphstbuf); return NULL; } free(tmphstbuf); } if(r < 0) { if(net_errno == NET_EINPROGRESS) { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT; pfd.revents = 0; r = netPoll(&pfd, 1, timeout); if(r == 0) { /* Timeout */ snprintf(errbuf, errbufsize, "Connection attempt timed out"); netClose(fd); return NULL; } if(r == -1) { snprintf(errbuf, errbufsize, "poll() error: %s", strerror(net_errno)); netClose(fd); return NULL; } netGetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen); } else { err = net_errno; } } else { err = 0; } if(err != 0) { snprintf(errbuf, errbufsize, "%s", strerror(err)); netClose(fd); return NULL; } optval = 0; r = netSetSockOpt(fd, SOL_SOCKET, SO_NBIO, &optval, sizeof(optval)); if(r < 0) { snprintf(errbuf, errbufsize, "Unable to go blocking: %s", strerror(net_errno)); netClose(fd); return NULL; } tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = fd; htsbuf_queue_init(&tc->spill, 0); if(ssl) { #if ENABLE_POLARSSL if(1) { tc->ssl = malloc(sizeof(ssl_context)); if(ssl_init(tc->ssl)) { snprintf(errbuf, errlen, "SSL failed to initialize"); close(fd); free(tc->ssl); free(tc); return NULL; } tc->ssn = malloc(sizeof(ssl_session)); tc->hs = malloc(sizeof(havege_state)); havege_init(tc->hs); memset(tc->ssn, 0, sizeof(ssl_session)); ssl_set_endpoint(tc->ssl, SSL_IS_CLIENT ); ssl_set_authmode(tc->ssl, SSL_VERIFY_NONE ); ssl_set_rng(tc->ssl, havege_rand, tc->hs ); ssl_set_bio(tc->ssl, net_recv, &tc->fd, net_send, &tc->fd); ssl_set_ciphers(tc->ssl, ssl_default_ciphers ); ssl_set_session(tc->ssl, 1, 600, tc->ssn ); tc->read = polarssl_read; tc->write = polarssl_write; } else #endif { snprintf(errbuf, errlen, "SSL not supported"); tcp_close(tc); return NULL; } } else { tc->read = tcp_read; tc->write = tcp_write; } return tc; }
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 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 * 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; }