src/input.c \
src/httpc.c \
src/rtsp.c \
+ src/download.c \
src/fsmonitor.c \
src/cron.c \
src/esfilter.c \
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
#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;
+
/*
*
*/
*
*/
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;
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);
}
/*
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);
+ }
}
/*
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);
}
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);
}
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;
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 );