From d6be48e207751c2058be5b27cb0bf7c8ee89e69a Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Mon, 28 Jun 2021 18:03:51 +0000 Subject: [PATCH 1/4] Update: Added stubs format_text.[ch] for text streaming See: #2084 --- src/Makefile.am | 2 ++ src/format_text.c | 20 ++++++++++++++++++++ src/format_text.h | 16 ++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/format_text.c create mode 100644 src/format_text.h diff --git a/src/Makefile.am b/src/Makefile.am index 8bff44c1..5796bcc0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ noinst_HEADERS = \ format_ogg.h \ format_mp3.h \ format_ebml.h \ + format_text.h \ format_vorbis.h \ format_theora.h \ format_flac.h \ @@ -100,6 +101,7 @@ icecast_SOURCES = \ format_midi.c \ format_flac.c \ format_ebml.c \ + format_text.c \ format_kate.c \ format_skeleton.c \ format_opus.c \ diff --git a/src/format_text.c b/src/format_text.c new file mode 100644 index 00000000..c83e7015 --- /dev/null +++ b/src/format_text.c @@ -0,0 +1,20 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, + * version 2. A copy of this license is included with this source. + * At your option, this specific source file can also be distributed + * under the GNU GPL version 3. + * + * Copyright 2021, Philipp "ph3-der-loewe" Schafft , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "format_text.h" + +#define CATMODULE "format-text" + +#include "logging.h" + diff --git a/src/format_text.h b/src/format_text.h new file mode 100644 index 00000000..58ce42ac --- /dev/null +++ b/src/format_text.h @@ -0,0 +1,16 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2021, Philipp "ph3-der-loewe" Schafft , + */ + +#ifndef __FORMAT_TEXT_H__ +#define __FORMAT_TEXT_H__ + +#include "format.h" + +int format_text_get_plugin(source_t *source); + +#endif /* __FORMAT_TEXT_H__ */ From b7c878cee90c4475f697cac046fcb5d64be9e21d Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Mon, 28 Jun 2021 18:57:02 +0000 Subject: [PATCH 2/4] Feature: Added basic text streaming support See: #2084 --- src/format.c | 5 +++++ src/format.h | 1 + src/format_text.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/src/format.c b/src/format.c index cd775d46..6f40bea2 100644 --- a/src/format.c +++ b/src/format.c @@ -71,6 +71,8 @@ format_type_t format_get_type (const char *contenttype) return FORMAT_TYPE_EBML; else if(strcmp(contenttype, "video/x-matroska-3d") == 0) return FORMAT_TYPE_EBML; + else if(strcmp(contenttype, "text/plain") == 0) + return FORMAT_TYPE_TEXT; else /* We default to the Generic format handler, which can handle many more formats than just mp3. @@ -90,6 +92,9 @@ int format_get_plugin(format_type_t type, source_t *source) case FORMAT_TYPE_EBML: ret = format_ebml_get_plugin(source); break; + case FORMAT_TYPE_TEXT: + ret = format_text_get_plugin(source); + break; case FORMAT_TYPE_GENERIC: ret = format_mp3_get_plugin(source); break; diff --git a/src/format.h b/src/format.h index 5ddae298..67c938f6 100644 --- a/src/format.h +++ b/src/format.h @@ -32,6 +32,7 @@ typedef enum _format_type_tag FORMAT_ERROR, /* No format, source not processable */ FORMAT_TYPE_OGG, FORMAT_TYPE_EBML, + FORMAT_TYPE_TEXT, FORMAT_TYPE_GENERIC } format_type_t; diff --git a/src/format_text.c b/src/format_text.c index c83e7015..41804bec 100644 --- a/src/format_text.c +++ b/src/format_text.c @@ -12,9 +12,63 @@ #include #endif +#include + +#include "source.h" +#include "format.h" #include "format_text.h" #define CATMODULE "format-text" #include "logging.h" +static void text_free_plugin(format_plugin_t *plugin) +{ + free(plugin); +} + +static refbuf_t *text_get_buffer(source_t *source) +{ + format_plugin_t *format = source->format; + refbuf_t *refbuf = refbuf_new(1024); + ssize_t bytes; + + bytes = client_body_read(source->client, refbuf->data, refbuf->len); + if (bytes < 0) { + /* Why do we do this here (not source.c)? -- ph3-der-loewe, 2018-04-17 */ + if (client_body_eof(source->client)) { + refbuf_release (refbuf); + } + return NULL; + } + refbuf->len = bytes; + refbuf->sync_point = 1; + format->read_bytes += bytes; + + ICECAST_LOG_DDEBUG("Got buffer for source %p with %zi bytes", source, bytes); + + return refbuf; +} + +int format_text_get_plugin(source_t *source) +{ + format_plugin_t *plugin = calloc(1, sizeof(format_plugin_t)); + + ICECAST_LOG_DEBUG("Opening text format for source %p", source); + + plugin->get_buffer = text_get_buffer; + plugin->write_buf_to_client = format_generic_write_to_client; + plugin->create_client_data = NULL; + plugin->free_plugin = text_free_plugin; + plugin->write_buf_to_file = NULL; + plugin->set_tag = NULL; + plugin->apply_settings = NULL; + + plugin->contenttype = httpp_getvar(source->parser, "content-type"); + + plugin->_state = NULL; + vorbis_comment_init(&plugin->vc); + source->format = plugin; + + return 0; +} From a24f74af11d744f855fa787671eca461462724d2 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 26 Oct 2021 02:08:59 +0000 Subject: [PATCH 3/4] Fix: Added missing include --- src/format.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/format.c b/src/format.c index 6f40bea2..06e656c1 100644 --- a/src/format.c +++ b/src/format.c @@ -43,6 +43,7 @@ #include "format_ogg.h" #include "format_mp3.h" #include "format_ebml.h" +#include "format_text.h" #include "logging.h" #include "stats.h" From ab915b061fbfa06be1644871229844d2c071284c Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 26 Oct 2021 09:37:40 +0000 Subject: [PATCH 4/4] Feature: Added experimental feature to skip characters on text/plain mounts (they are used for keep-alive) --- src/format_text.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/format_text.c b/src/format_text.c index 41804bec..2b22be64 100644 --- a/src/format_text.c +++ b/src/format_text.c @@ -13,6 +13,7 @@ #endif #include +#include #include "source.h" #include "format.h" @@ -22,14 +23,42 @@ #include "logging.h" +typedef struct { + bool skipchar; + char skipchar_char; +} text_state_t; + static void text_free_plugin(format_plugin_t *plugin) { + free(plugin->_state); free(plugin); } +static size_t skipchar(char *text, char skip, size_t len) +{ + char *inp = text; + char *outp = text; + size_t ret = 0; + + // skip prefix. + for (; len && *inp != skip; inp++, outp++, len--, ret++); + + for (; len; inp++, len--) { + if (*inp != skip) { + *outp = *inp; + outp++; + ret++; + } + } + + return ret; +} + + static refbuf_t *text_get_buffer(source_t *source) { format_plugin_t *format = source->format; + text_state_t *state = format->_state; refbuf_t *refbuf = refbuf_new(1024); ssize_t bytes; @@ -41,6 +70,10 @@ static refbuf_t *text_get_buffer(source_t *source) } return NULL; } + + if (state->skipchar) + bytes = skipchar(refbuf->data, state->skipchar_char, bytes); + refbuf->len = bytes; refbuf->sync_point = 1; format->read_bytes += bytes; @@ -53,6 +86,8 @@ static refbuf_t *text_get_buffer(source_t *source) int format_text_get_plugin(source_t *source) { format_plugin_t *plugin = calloc(1, sizeof(format_plugin_t)); + text_state_t *state = calloc(1, sizeof(text_state_t)); + const char *skip; ICECAST_LOG_DEBUG("Opening text format for source %p", source); @@ -66,7 +101,33 @@ int format_text_get_plugin(source_t *source) plugin->contenttype = httpp_getvar(source->parser, "content-type"); - plugin->_state = NULL; + skip = httpp_getvar(source->parser, "x-icecast-text-skip-char"); + if (skip) { + ICECAST_LOG_WARN("Source %p on mount %#H uses experimental X-Icecast-Text-Skip-Char:-header", source, source->mount); + } + if (skip && strlen(skip) == 3 && skip[0] == '%') { + bool valid = true; + size_t i; + + for (i = 1; i < 3; i++) { + const char c = skip[i]; + + state->skipchar_char <<= 4; + if (c >= '0' && c <= '9') { + state->skipchar_char += c - '0'; + } else if (c >= 'a' && c <= 'f') { + state->skipchar_char += c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + state->skipchar_char += c - 'A' + 10; + } else { + valid = false; + } + } + + state->skipchar = valid; + } + + plugin->_state = state; vorbis_comment_init(&plugin->vc); source->format = plugin;