From: Jaroslav Kysela Date: Wed, 14 Oct 2015 14:59:51 +0000 (+0200) Subject: download: moved common download routines from iptv_auto.c to src/download.c X-Git-Tag: v4.2.1~1912 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0697ed22ef2f0d2df883db3431c1bf22c7e871c9;p=thirdparty%2Ftvheadend.git download: moved common download routines from iptv_auto.c to src/download.c --- diff --git a/Makefile b/Makefile index 730ec70ba..5df514858 100644 --- 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 index 000000000..12ae3f931 --- /dev/null +++ b/src/download.c @@ -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 . + */ + +#include "tvheadend.h" +#include "download.h" + +#include +#include + +/* + * + */ +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 index 000000000..0f1b817e5 --- /dev/null +++ b/src/download.h @@ -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 . + */ + +#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__ */ diff --git a/src/input/mpegts/iptv/iptv_auto.c b/src/input/mpegts/iptv/iptv_auto.c index aaac38fca..c3f1a801b 100644 --- a/src/input/mpegts/iptv/iptv_auto.c +++ b/src/input/mpegts/iptv/iptv_auto.c @@ -21,10 +21,17 @@ #include "http.h" #include "iptv_private.h" #include "channels.h" +#include "download.h" #include #include +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); } diff --git a/src/input/mpegts/iptv/iptv_private.h b/src/input/mpegts/iptv/iptv_private.h index 3803e8ce2..f12734809 100644 --- a/src/input/mpegts/iptv/iptv_private.h +++ b/src/input/mpegts/iptv/iptv_private.h @@ -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 );