From a609cd2edb3457d0e1c527005b4c312748b0480d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 12 Dec 2014 12:06:55 +0100 Subject: [PATCH] HTTP dvrfile streaming: add subscription handling - fixes #2540 --- src/subscriptions.c | 4 ++++ src/subscriptions.h | 1 + src/webui/webui.c | 51 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/subscriptions.c b/src/subscriptions.c index 1c0a08b1..298d7f39 100644 --- a/src/subscriptions.c +++ b/src/subscriptions.c @@ -561,6 +561,7 @@ subscription_unsubscribe(th_subscription_t *s) free(s->ths_hostname); free(s->ths_username); free(s->ths_client); + free(s->ths_dvrfile); free(s); gtimer_arm(&subscription_reschedule_timer, @@ -894,6 +895,9 @@ subscription_create_msg(th_subscription_t *s) if(s->ths_service != NULL) htsmsg_add_str(m, "service", s->ths_service->s_nicename ?: ""); + else if(s->ths_dvrfile != NULL) + htsmsg_add_str(m, "service", s->ths_dvrfile ?: ""); + else if (s->ths_mmi != NULL && s->ths_mmi->mmi_mux != NULL) { char buf[512]; mpegts_mux_t *mm = s->ths_mmi->mmi_mux; diff --git a/src/subscriptions.h b/src/subscriptions.h index ca22d3c5..40c638de 100644 --- a/src/subscriptions.h +++ b/src/subscriptions.h @@ -95,6 +95,7 @@ typedef struct th_subscription { char *ths_hostname; char *ths_username; char *ths_client; + char *ths_dvrfile; /** * This is the list of service candidates we have diff --git a/src/webui/webui.c b/src/webui/webui.c index 98e4f1c9..4dff23e9 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -1097,7 +1097,7 @@ page_play(http_connection_t *hc, const char *remain, void *opaque) static int page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) { - int fd, i; + int fd, i, ret; struct stat st; const char *content = NULL, *range; dvr_entry_t *de; @@ -1107,6 +1107,8 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) char disposition[256]; off_t content_len, chunk; intmax_t file_start, file_end; + void *tcp_id; + th_subscription_t *sub; #if defined(PLATFORM_LINUX) ssize_t r; #elif defined(PLATFORM_FREEBSD) || defined(PLATFORM_DARWIN) @@ -1133,7 +1135,7 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) return HTTP_STATUS_NOT_FOUND; } - fname = strdup(de->de_filename); + fname = tvh_strdupa(de->de_filename); content = muxer_container_type2mime(de->de_mc, 1); pthread_mutex_unlock(&global_lock); @@ -1153,7 +1155,6 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) } fd = tvh_open(fname, O_RDONLY, 0); - free(fname); if(fd < 0) return HTTP_STATUS_NOT_FOUND; @@ -1195,14 +1196,40 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) return HTTP_STATUS_INTERNAL; } + pthread_mutex_lock(&global_lock); + tcp_id = http_stream_preop(hc); + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, range_buf, 50); + sub = NULL; + if (tcp_id && !hc->hc_no_output && content_len > 64*1024) { + sub = subscription_create(NULL, 1, "HTTP", + SUBSCRIPTION_NONE, NULL, + range_buf, hc->hc_username, + http_arg_get(&hc->hc_args, "User-Agent")); + if (sub == NULL) { + http_stream_postop(tcp_id); + tcp_id = NULL; + } else { + basename = malloc(strlen(fname) + 7 + 1); + strcpy(basename, "file://"); + strcat(basename, fname); + sub->ths_dvrfile = basename; + } + } + pthread_mutex_unlock(&global_lock); + if (tcp_id == NULL) { + close(fd); + return HTTP_STATUS_NOT_ALLOWED; + } + http_send_header(hc, range ? HTTP_STATUS_PARTIAL_CONTENT : HTTP_STATUS_OK, content, content_len, NULL, NULL, 10, range ? range_buf : NULL, disposition[0] ? disposition : NULL); + ret = 0; if(!hc->hc_no_output) { while(content_len > 0) { - chunk = MIN(1024 * 1024 * 1024, content_len); + chunk = MIN(1024 * (sub ? 128 : 1024 * 1024), content_len); #if defined(PLATFORM_LINUX) r = sendfile(hc->hc_fd, fd, NULL, chunk); #elif defined(PLATFORM_FREEBSD) @@ -1212,14 +1239,24 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) sendfile(fd, hc->hc_fd, 0, NULL, &r, 0); #endif if(r < 0) { - close(fd); - return -1; + ret = -1; + break; } content_len -= r; + if (sub) { + sub->ths_bytes_in += r; + sub->ths_bytes_out += r; + } } } close(fd); - return 0; + + pthread_mutex_lock(&global_lock); + if (sub) + subscription_unsubscribe(sub); + http_stream_postop(tcp_id); + pthread_mutex_unlock(&global_lock); + return ret; } /**