From: Jaroslav Kysela Date: Thu, 12 Nov 2015 16:53:00 +0000 (+0100) Subject: download: add pipe:// support, fixes #3221 X-Git-Tag: v4.2.1~1563 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=91b153861c00ef78ed54da61686fe3465dcb5d88;p=thirdparty%2Ftvheadend.git download: add pipe:// support, fixes #3221 --- diff --git a/src/download.c b/src/download.c index 3b37fcc36..b9aa9450d 100644 --- a/src/download.c +++ b/src/download.c @@ -19,7 +19,9 @@ #include "tvheadend.h" #include "download.h" +#include "spawn.h" +#include #include #include @@ -154,6 +156,103 @@ out: return 0; } +/* + * + */ +static void +download_pipe_close(download_t *dn) +{ + if (dn->pipe_fd >= 0) { + close(dn->pipe_fd); + if (dn->pipe_pid) + kill(-(dn->pipe_pid), SIGKILL); /* kill whole process group */ + dn->pipe_fd = -1; + dn->pipe_pid = 0; + } + sbuf_free(&dn->pipe_sbuf); +} + +/* + * + */ +static void +download_pipe_read(void *aux) +{ + download_t *dn = aux; + ssize_t len; + char *s, *p; + + if (dn->pipe_fd < 0 || dn->pipe_pid == 0) + return; + + while (1) { + if (dn->pipe_sbuf.sb_ptr > 50*1024*1024) { + errno = EMSGSIZE; + goto failed; + } + sbuf_alloc(&dn->pipe_sbuf, 2048); + len = sbuf_read(&dn->pipe_sbuf, dn->pipe_fd); + if (len == 0) { + s = dn->url ? strdupa(dn->url) : strdupa(""); + p = strchr(s, ' '); + if (p) + *p = '\0'; + p = strrchr(s, '/'); + if (p) + p++; + sbuf_append(&dn->pipe_sbuf, "", 1); + dn->process(dn->aux, p, NULL, (char *)dn->pipe_sbuf.sb_data, (size_t)dn->pipe_sbuf.sb_ptr); + download_pipe_close(dn); + return; + } else if (len < 0) { + if (ERRNO_AGAIN(errno)) + break; +failed: + tvherror(dn->log, "pipe: read failed: %d", errno); + download_pipe_close(dn); + return; + } + } + + gtimer_arm_ms(&dn->pipe_read_timer, download_pipe_read, dn, 250); +} + +/* + * + */ +static int +download_pipe(download_t *dn, const char *args) +{ + char **argv = NULL; + int r; + + download_pipe_close(dn); + gtimer_disarm(&dn->pipe_read_timer); + + /* Arguments */ + if (spawn_parse_args(&argv, 64, args, NULL)) { + tvherror(dn->log, "pipe: unable to parse arguments (%s)", args); + return NULL; + } + + /* Grab */ + r = spawn_and_give_stdout(argv[0], argv, NULL, &dn->pipe_fd, &dn->pipe_pid, 1); + + spawn_free_args(argv); + + if (r < 0) { + dn->pipe_fd = -1; + dn->pipe_pid = 0; + tvherror(LOG_ERR, dn->log, "pipe: cannot start (%s)", args); + return -1; + } + + fcntl(dn->pipe_fd, F_SETFL, fcntl(dn->pipe_fd, F_GETFL) | O_NONBLOCK); + + gtimer_arm_ms(&dn->pipe_read_timer, download_pipe_read, dn, 250); + return 0; +} + /* * */ @@ -174,6 +273,11 @@ download_fetch(void *aux) goto done; } + if (strncmp(dn->url, "pipe://", 7) == 0) { + download_pipe(dn, dn->url + 7); + goto done; + } + if (dn->http_client) { http_client_close(dn->http_client); dn->http_client = NULL; @@ -217,6 +321,8 @@ download_init( download_t *dn, const char *log ) { memset(dn, 0, sizeof(*dn)); dn->log = strdup(log); + dn->pipe_fd = -1; + sbuf_init(&dn->pipe_sbuf); } /* @@ -247,7 +353,9 @@ download_done( download_t *dn ) http_client_close(dn->http_client); dn->http_client = NULL; } + download_pipe_close(dn); gtimer_disarm(&dn->fetch_timer); + gtimer_disarm(&dn->pipe_read_timer); free(dn->log); dn->log = NULL; free(dn->url); dn->url = NULL; } diff --git a/src/download.h b/src/download.h index a050f15a3..3322d77b3 100644 --- a/src/download.h +++ b/src/download.h @@ -26,13 +26,17 @@ typedef struct download { char *log; char *url; void *aux; - int ssl_peer_verify; + int ssl_peer_verify; int (*process)(void *aux, const char *last_url, const char *host_url, char *data, size_t len); void (*stop)(void *aux); /* internal members */ http_client_t *http_client; - gtimer_t fetch_timer; + gtimer_t fetch_timer; + gtimer_t pipe_read_timer; + sbuf_t pipe_sbuf; + int pipe_fd; + pid_t pipe_pid; } download_t; void download_init ( download_t *dn, const char *log ); diff --git a/src/input/mpegts/iptv/iptv.c b/src/input/mpegts/iptv/iptv.c index 45c3ff9d0..61237dca7 100644 --- a/src/input/mpegts/iptv/iptv.c +++ b/src/input/mpegts/iptv/iptv.c @@ -652,7 +652,7 @@ static int iptv_auto_network_class_url_set( void *in, const void *v ) { iptv_network_t *mn = in; - return iptv_url_set(&mn->in_url, &mn->in_url_sane, v, 1, 0); + return iptv_url_set(&mn->in_url, &mn->in_url_sane, v, 1, 1); } static void diff --git a/src/input/mpegts/iptv/iptv_mux.c b/src/input/mpegts/iptv/iptv_mux.c index d06afb019..91011671e 100644 --- a/src/input/mpegts/iptv/iptv_mux.c +++ b/src/input/mpegts/iptv/iptv_mux.c @@ -82,6 +82,9 @@ iptv_url_set ( char **url, char **sane_url, const char *str, int allow_file, int iptv_url_set0(url, sane_url, str, buf); urlreset(&u); return 1; + } else { + if (*url == NULL || **url == '\0') + iptv_url_set0(url, sane_url, "?", "?"); } return 0;