]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
download: moved common download routines from iptv_auto.c to src/download.c
authorJaroslav Kysela <perex@perex.cz>
Wed, 14 Oct 2015 14:59:51 +0000 (16:59 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 14 Oct 2015 14:59:51 +0000 (16:59 +0200)
Makefile
src/download.c [new file with mode: 0644]
src/download.h [new file with mode: 0644]
src/input/mpegts/iptv/iptv_auto.c
src/input/mpegts/iptv/iptv_private.h

index 730ec70bad197ecc4f4bbc06abca5d1f6dc00e1b..5df51485861cf6208d7d710d8d880e7a8501db9a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -191,6 +191,7 @@ SRCS-1 = \
        src/input.c \
        src/httpc.c \
        src/rtsp.c \
+       src/download.c \
        src/fsmonitor.c \
        src/cron.c \
        src/esfilter.c \
diff --git a/src/download.c b/src/download.c
new file mode 100644 (file)
index 0000000..12ae3f9
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  Download a file from storage or network
+ *
+ *  Copyright (C) 2015 Jaroslav Kysela
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tvheadend.h"
+#include "download.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/*
+ *
+ */
+static int
+download_file(download_t *dn, const char *filename)
+{
+  int fd, res;
+  struct stat st;
+  char *data, *last_url;
+  size_t r;
+  off_t off;
+
+  fd = tvh_open(filename, O_RDONLY, 0);
+  if (fd < 0) {
+    tvherror(dn->log, "unable to open file '%s': %s",
+             filename, strerror(errno));
+    return -1;
+  }
+  if (fstat(fd, &st) || st.st_size == 0) {
+    tvherror(dn->log, "unable to stat file '%s': %s",
+             filename, strerror(errno));
+    close(fd);
+    return -1;
+  }
+  data = malloc(st.st_size+1);
+  off = 0;
+  do {
+    r = read(fd, data + off, st.st_size - off);
+    if (r < 0) {
+      if (ERRNO_AGAIN(errno))
+        continue;
+      break;
+    }
+    off += r;
+  } while (off != st.st_size);
+  close(fd);
+
+  if (off == st.st_size) {
+    data[off] = '\0';
+    last_url = strrchr(filename, '/');
+    if (last_url)
+      last_url++;
+    res = dn->process(dn->aux, last_url, data, off);
+  } else {
+    res = -1;
+  }
+  free(data);
+  return res;
+}
+
+/*
+ *
+ */
+static void
+download_fetch_done(void *aux)
+{
+  http_client_t *hc = aux;
+  download_t *dm = hc->hc_aux;
+  if (dm->http_client) {
+    dm->http_client = NULL;
+    http_client_close((http_client_t *)aux);
+  }
+}
+
+/*
+ *
+ */
+static int
+download_fetch_complete(http_client_t *hc)
+{
+  download_t *dn = hc->hc_aux;
+  char *last_url = NULL;
+  url_t u;
+
+  switch (hc->hc_code) {
+  case HTTP_STATUS_MOVED:
+  case HTTP_STATUS_FOUND:
+  case HTTP_STATUS_SEE_OTHER:
+  case HTTP_STATUS_NOT_MODIFIED:
+    return 0;
+  }
+
+  urlinit(&u);
+  if (!urlparse(dn->url, &u)) {
+    last_url = strrchr(u.path, '/');
+    if (last_url)
+      last_url++;
+  }
+
+  pthread_mutex_lock(&global_lock);
+
+  if (dn->http_client == NULL)
+    goto out;
+
+  if (hc->hc_code == HTTP_STATUS_OK && hc->hc_result == 0 && hc->hc_data_size > 0)
+    dn->process(dn->aux, last_url, hc->hc_data, hc->hc_data_size);
+  else
+    tvherror(dn->log, "unable to fetch data from url [%d-%d/%zd]",
+             hc->hc_code, hc->hc_result, hc->hc_data_size);
+
+  /* note: http_client_close must be called outside http_client callbacks */
+  gtimer_arm(&dn->fetch_timer, download_fetch_done, hc, 0);
+
+out:
+  pthread_mutex_unlock(&global_lock);
+
+  urlreset(&u);
+  return 0;
+}
+
+/*
+ *
+ */
+static void
+download_fetch(void *aux)
+{
+  download_t *dn = aux;
+  http_client_t *hc;
+  url_t u;
+
+  urlinit(&u);
+
+  if (dn->url == NULL)
+    goto done;
+
+  if (strncmp(dn->url, "file://", 7) == 0) {
+    download_file(dn, dn->url + 7);
+    goto done;
+  }
+
+  if (dn->http_client) {
+    http_client_close(dn->http_client);
+    dn->http_client = NULL;
+  }
+
+  if (urlparse(dn->url, &u) < 0) {
+    tvherror(dn->log, "wrong url");
+    goto stop;
+  }
+  hc = http_client_connect(dn, HTTP_VERSION_1_1, u.scheme, u.host, u.port, NULL);
+  if (hc == NULL) {
+    tvherror(dn->log, "unable to open http client");
+    goto stop;
+  }
+  hc->hc_handle_location = 1;
+  hc->hc_data_limit = 1024*1024;
+  hc->hc_data_complete = download_fetch_complete;
+  http_client_register(hc);
+  http_client_ssl_peer_verify(hc, dn->ssl_peer_verify);
+  if (http_client_simple(hc, &u) < 0) {
+    http_client_close(hc);
+    tvherror(dn->log, "unable to send http command");
+    goto stop;
+  }
+
+  dn->http_client = hc;
+  goto done;
+
+stop:
+  if (dn->stop)
+    dn->stop(dn->aux);
+done:
+  urlreset(&u);
+}
+
+/*
+ *
+ */
+void
+download_init( download_t *dn, const char *log )
+{
+  memset(dn, 0, sizeof(*dn));
+  dn->log = strdup(log);
+}
+
+/*
+ *
+ */
+void
+download_start( download_t *dn, const char *url, void *aux )
+{
+  if (dn->http_client) {
+    http_client_close(dn->http_client);
+    dn->http_client = NULL;
+  }
+  if (url)
+    dn->url = strdup(url);
+  dn->aux = aux;
+  gtimer_arm(&dn->fetch_timer, download_fetch, dn, 0);
+}
+
+/*
+ *
+ */
+void
+download_done( download_t *dn )
+{
+  if (dn->http_client) {
+    http_client_close(dn->http_client);
+    dn->http_client = NULL;
+  }
+  gtimer_disarm(&dn->fetch_timer);
+  free(dn->log); dn->log = NULL;
+  free(dn->url); dn->url = NULL;
+}
diff --git a/src/download.h b/src/download.h
new file mode 100644 (file)
index 0000000..0f1b817
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  Download a file from storage or network
+ *
+ *  Copyright (C) 2015 Jaroslav Kysela
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DOWNLOAD__
+#define __DOWNLOAD__
+
+#include "http.h"
+
+typedef struct download {
+  char *log;
+  char *url;
+  void *aux;
+  int ssl_peer_verify;
+  int (*process)(void *aux, const char *last_url, char *data, size_t len);
+  void (*stop)(void *aux);
+  /* internal members */
+  http_client_t *http_client;
+  gtimer_t fetch_timer;
+} download_t;
+
+void download_init ( download_t *dn, const char *log );
+void download_start( download_t *dn, const char *url, void *aux );
+void download_done ( download_t *dn );
+
+#endif /* __DOWNLOAD__ */
index aaac38fca71fff208f9020af423dea80090f9183..c3f1a801bf7810b643f8cefb1c165ec89206f930 100644 (file)
 #include "http.h"
 #include "iptv_private.h"
 #include "channels.h"
+#include "download.h"
 
 #include <fcntl.h>
 #include <sys/stat.h>
 
+typedef struct auto_private {
+  iptv_network_t *in_network;
+  download_t      in_download;
+  gtimer_t        in_auto_timer;
+} auto_private_t;
+
 /*
  *
  */
@@ -253,8 +260,10 @@ iptv_auto_network_process_m3u(iptv_network_t *in, char *data,
  *
  */
 static int
-iptv_auto_network_process(iptv_network_t *in, const char *last_url, char *data, size_t len)
+iptv_auto_network_process(void *aux, const char *last_url, char *data, size_t len)
 {
+  auto_private_t *ap = aux;
+  iptv_network_t *in = ap->in_network;
   mpegts_mux_t *mm;
   int r = -1, count, n, i;
   http_arg_list_t remove_args;
@@ -299,168 +308,28 @@ iptv_auto_network_process(iptv_network_t *in, const char *last_url, char *data,
   return -1;
 }
 
-/*
- *
- */
-static int
-iptv_auto_network_file(iptv_network_t *in, const char *filename)
-{
-  int fd, res;
-  struct stat st;
-  char *data, *last_url;
-  size_t r;
-  off_t off;
-
-  fd = tvh_open(filename, O_RDONLY, 0);
-  if (fd < 0) {
-    tvherror("iptv", "unable to open file '%s' (network '%s'): %s",
-             filename, in->mn_network_name, strerror(errno));
-    return -1;
-  }
-  if (fstat(fd, &st) || st.st_size == 0) {
-    tvherror("iptv", "unable to stat file '%s' (network '%s'): %s",
-             filename, in->mn_network_name, strerror(errno));
-    close(fd);
-    return -1;
-  }
-  data = malloc(st.st_size+1);
-  off = 0;
-  do {
-    r = read(fd, data + off, st.st_size - off);
-    if (r < 0) {
-      if (ERRNO_AGAIN(errno))
-        continue;
-      break;
-    }
-    off += r;
-  } while (off != st.st_size);
-  close(fd);
-
-  if (off == st.st_size) {
-    data[off] = '\0';
-    last_url = strrchr(filename, '/');
-    if (last_url)
-      last_url++;
-    res = iptv_auto_network_process(in, last_url, data, off);
-  } else {
-    res = -1;
-  }
-  free(data);
-  return res;
-}
-
 /*
  *
  */
 static void
-iptv_auto_network_fetch_done(void *aux)
+iptv_auto_network_stop( void *aux )
 {
-  http_client_t *hc = aux;
-  iptv_network_t *in = hc->hc_aux;
-  if (in->in_http_client) {
-    in->in_http_client = NULL;
-    http_client_close((http_client_t *)aux);
-  }
-}
-
-/*
- *
- */
-static int
-iptv_auto_network_fetch_complete(http_client_t *hc)
-{
-  iptv_network_t *in = hc->hc_aux;
-  char *last_url = NULL;
-  url_t u;
-
-  switch (hc->hc_code) {
-  case HTTP_STATUS_MOVED:
-  case HTTP_STATUS_FOUND:
-  case HTTP_STATUS_SEE_OTHER:
-  case HTTP_STATUS_NOT_MODIFIED:
-    return 0;
-  }
-
-  urlinit(&u);
-  if (!urlparse(in->in_url, &u)) {
-    last_url = strrchr(u.path, '/');
-    if (last_url)
-      last_url++;
-  }
-
-  pthread_mutex_lock(&global_lock);
-
-  if (in->in_http_client == NULL)
-    goto out;
-
-  if (hc->hc_code == HTTP_STATUS_OK && hc->hc_result == 0 && hc->hc_data_size > 0)
-    iptv_auto_network_process(in, last_url, hc->hc_data, hc->hc_data_size);
-  else
-    tvherror("iptv", "unable to fetch data from url for network '%s' [%d-%d/%zd]",
-             in->mn_network_name, hc->hc_code, hc->hc_result, hc->hc_data_size);
-
-  /* note: http_client_close must be called outside http_client callbacks */
-  gtimer_arm(&in->in_fetch_timer, iptv_auto_network_fetch_done, hc, 0);
-
-out:
-  pthread_mutex_unlock(&global_lock);
-
-  urlreset(&u);
-  return 0;
+  auto_private_t *ap = aux;
+  gtimer_disarm(&ap->in_auto_timer);
 }
 
 /*
  *
  */
 static void
-iptv_auto_network_fetch(void *aux)
+iptv_auto_network_trigger0(void *aux)
 {
-  iptv_network_t *in = aux;
-  http_client_t *hc;
-  url_t u;
-
-  urlinit(&u);
+  auto_private_t *ap = aux;
+  iptv_network_t *in = ap->in_network;
 
-  if (in->in_url == NULL)
-    goto done;
-
-  if (strncmp(in->in_url, "file://", 7) == 0) {
-    iptv_auto_network_file(in, in->in_url + 7);
-    goto done;
-  }
-
-  gtimer_disarm(&in->in_auto_timer);
-  if (in->in_http_client) {
-    http_client_close(in->in_http_client);
-    in->in_http_client = NULL;
-  }
-
-  if (urlparse(in->in_url, &u) < 0) {
-    tvherror("iptv", "wrong url for network '%s'", in->mn_network_name);
-    goto done;
-  }
-  hc = http_client_connect(in, HTTP_VERSION_1_1, u.scheme, u.host, u.port, NULL);
-  if (hc == NULL) {
-    tvherror("iptv", "unable to open http client for network '%s'", in->mn_network_name);
-    goto done;
-  }
-  hc->hc_handle_location = 1;
-  hc->hc_data_limit = 1024*1024;
-  hc->hc_data_complete = iptv_auto_network_fetch_complete;
-  http_client_register(hc);
-  http_client_ssl_peer_verify(hc, in->in_ssl_peer_verify);
-  if (http_client_simple(hc, &u) < 0) {
-    http_client_close(hc);
-    tvherror("iptv", "unable to send http command for network '%s'", in->mn_network_name);
-    goto done;
-  }
-
-  in->in_http_client = hc;
-
-  gtimer_arm(&in->in_auto_timer, iptv_auto_network_fetch, in,
+  download_start(&ap->in_download, in->in_url, ap);
+  gtimer_arm(&ap->in_auto_timer, iptv_auto_network_trigger0, in,
              MAX(1, in->in_refetch_period) * 60);
-done:
-  urlreset(&u);
 }
 
 /*
@@ -469,7 +338,11 @@ done:
 void
 iptv_auto_network_trigger( iptv_network_t *in )
 {
-  gtimer_arm(&in->in_auto_timer, iptv_auto_network_fetch, in, 0);
+  auto_private_t *ap = in->in_auto;
+  if (ap) {
+    ap->in_download.ssl_peer_verify = in->in_ssl_peer_verify;
+    iptv_auto_network_trigger0(ap);
+  }
 }
 
 /*
@@ -478,6 +351,12 @@ iptv_auto_network_trigger( iptv_network_t *in )
 void
 iptv_auto_network_init( iptv_network_t *in )
 {
+  auto_private_t *ap = calloc(1, sizeof(auto_private_t));
+  ap->in_network = in;
+  in->in_auto = ap;
+  download_init(&ap->in_download, "iptv");
+  ap->in_download.process = iptv_auto_network_process;
+  ap->in_download.stop = iptv_auto_network_stop;
   iptv_auto_network_trigger(in);
 }
 
@@ -487,10 +366,9 @@ iptv_auto_network_init( iptv_network_t *in )
 void
 iptv_auto_network_done( iptv_network_t *in )
 {
-  if (in->in_http_client) {
-    http_client_close(in->in_http_client);
-    in->in_http_client = NULL;
-  }
-  gtimer_disarm(&in->in_auto_timer);
-  gtimer_disarm(&in->in_fetch_timer);
+  auto_private_t *ap = in->in_auto;
+  in->in_auto = NULL;
+  gtimer_disarm(&ap->in_auto_timer);
+  download_done(&ap->in_download);
+  free(ap);
 }
index 3803e8ce22e8b310275229846ed93f6954eff89d..f1273480975505c8fb44b0140067cf062d5a30d7 100644 (file)
@@ -38,8 +38,6 @@
 
 extern pthread_mutex_t iptv_lock;
 
-struct http_client;
-
 typedef struct iptv_input   iptv_input_t;
 typedef struct iptv_network iptv_network_t;
 typedef struct iptv_mux     iptv_mux_t;
@@ -89,9 +87,8 @@ struct iptv_network
   char    *in_icon_url_sane;
   int      in_ssl_peer_verify;
   char    *in_remove_args;
-  gtimer_t in_auto_timer;
-  gtimer_t in_fetch_timer;
-  struct http_client *in_http_client;
+
+  void    *in_auto; /* private structure for auto-network */
 };
 
 iptv_network_t *iptv_network_create0 ( const char *uuid, htsmsg_t *conf, const idclass_t *idc );