]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
download: add pipe:// support, fixes #3221
authorJaroslav Kysela <perex@perex.cz>
Thu, 12 Nov 2015 16:53:00 +0000 (17:53 +0100)
committerJaroslav Kysela <perex@perex.cz>
Thu, 12 Nov 2015 18:02:53 +0000 (19:02 +0100)
src/download.c
src/download.h
src/input/mpegts/iptv/iptv.c
src/input/mpegts/iptv/iptv_mux.c

index 3b37fcc3660da6c6e37bf773d0de9bd08e876078..b9aa9450d129a73ab536f926ac8845de57b55057 100644 (file)
@@ -19,7 +19,9 @@
 
 #include "tvheadend.h"
 #include "download.h"
+#include "spawn.h"
 
+#include <signal.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 
@@ -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;
 }
index a050f15a3c63958c907b4f380b13705fc1e0cb63..3322d77b36495ff739acf0bfd025a3e41d7c1334 100644 (file)
@@ -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 );
index 45c3ff9d0aad8f7b7bf6489c816fcd85afeeba31..61237dca7336dd48eaa8e2c180bad8f140a6d1de 100644 (file)
@@ -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
index d06afb019c71a6f28ed1f82471bef7cf4a1b3ba9..91011671e39c235b32373aa67783283e158c39f7 100644 (file)
@@ -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;