1
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2024-09-15 04:08:07 -04:00

Merge branch 'release/0.6.0'

This commit is contained in:
Moritz Grimm 2015-01-18 01:22:10 +01:00
commit ee0700992e
32 changed files with 363 additions and 2210 deletions

16
.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
Makefile.in
aclocal.m4
compile
config.guess
config.h.in
config.sub
configure
depcomp
install-sh
libtool.m4
ltmain.sh
ltoptions.m4
ltsugar.m4
ltversion.m4
lt~obsolete.m4
missing

View File

@ -1,6 +1,6 @@
ezstream - source client for Icecast with external en-/decoder support
Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
The ezstream program, in its entirety, is licensed under the terms and

2025
ChangeLog

File diff suppressed because it is too large Load Diff

60
NEWS
View File

@ -1,3 +1,48 @@
Changes in 0.6.0, released on 2015-01-18:
* This release contains a SECURITY FIX for a command injection vulnerability
that was found and reported by Alexandre Rebert:
The previous handling of metadata placeholders allowed for arbitrary shell
commands to be trivially injected and executed as the ezstream user, via
malicious media files.
This vulnerability depends on both a configuration using metadata
placeholders and the user streaming media files from untrusted sources
without noticing `commands` or $(commands) in artist or title fields.
While the group of actually affected users may be limited, all users are
advised to upgrade.
* This release requires users to ADJUST their CONFIGURATION:
To protect against the injection vulnerability above, metadata is now
properly quoted and escaped from the shell. This means that any extra
quoting must be removed from configuration files.
Remove all quoting from metadata placeholders in <encode/> and <decode/>
commands, e.g. replace "@M@" with @M@, and "@T@" with @T@, etc. Without
these changes, stream metadata will look both wrong and the injection
vulnerability may be re-introduced.
Configuration examples have been adjusted accordingly.
* src/ezstream.c:
- [FIX] Prevent certain characters from being interpreted by the shell.
- [FIX] Prevent ezstream from entering an infinite loop when stopping to
send data to standard input. From gquintard.
(Ticket #2045)
* various:
- [NEW] Add new <metadata_refreshinterval/> feature from Matthew Adams
(with minor changes plus documentation.) This allows for recurring
and custom metadata updates in between song changes via
<metadata_progname/>.
- [NEW] Add new command line option `-m' to disable any active metadata
updates. Idea from Richard Thomas.
(Ticket #1620)
Changes in 0.5.6, released on 2009-08-31:
* ezstream-file.sh:
@ -23,6 +68,7 @@ Changes in 0.5.6, released on 2009-08-31:
- [NEW] Add a real-world example playlist script with logging feature.
Changes in 0.5.5, released on 2009-08-01:
* win32/config.h:
@ -177,7 +223,7 @@ Changes in 0.4.0, released on 2007-03-11:
program.
* src/compat.c:
- [ADD] Implement a basename() function for Windows that behaves like the
- [NEW] Implement a basename() function for Windows that behaves like the
ones used on Unix systems.
* win32/:
@ -185,19 +231,19 @@ Changes in 0.4.0, released on 2007-03-11:
distribution, and provide a much better PDF version instead.
* various:
- [ADD] Allow ezstream to use TagLib for reading metadata from media
- [NEW] Allow ezstream to use TagLib for reading metadata from media
files. TagLib (libtag_c) is now an optional dependency.
- [ADD] When built with TagLib support, include the song length in the
- [NEW] When built with TagLib support, include the song length in the
"real-time" information line, if available.
- [ADD] New <metadata_progname> configuration option, which causes
- [NEW] New <metadata_progname> configuration option, which causes
metadata to be read from the output of an external program or
script.
- [ADD] New runtime control via the SIGUSR2 signal, which triggers reading
- [NEW] New runtime control via the SIGUSR2 signal, which triggers reading
of fresh metadata information from <metadata_progname> (metadata
is always read at song changes.)
- [ADD] New <metadata_format> configuration option, to customize metadata
- [NEW] New <metadata_format> configuration option, to customize metadata
strings when used with the new <metadata_progname> feature.
- [ADD] New '@a@' and '@t@' placeholders for separate artist and title
- [NEW] New '@a@' and '@t@' placeholders for separate artist and title
metadata in de-/encoder commands.

4
README
View File

@ -40,7 +40,7 @@ Ezstream optionally uses:
- For reading metadata from Ogg Vorbis files:
* TagLib 1.x (1.4 or newer recommended, will be used via the libtag_c
wrapper)
(http://developer.kde.org/~wheeler/taglib.html)
(https://taglib.github.io/)
OR:
* libvorbis 1.x
(http://www.vorbis.com)
@ -48,7 +48,7 @@ Ezstream optionally uses:
many additional media file types.
- For basic non-ASCII charset support in metadata and filenames:
* Libiconv, if iconv() is not available in the system libc.
(http://www.gnu.org/software/libiconv/)
(https://www.gnu.org/software/libiconv/)

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: tree.3,v 1.20 2009/01/28 12:22:48 stsp Exp $
.\" $OpenBSD: tree.3,v 1.26 2014/09/08 01:27:55 schwarze Exp $
.\"/*
.\" * Copyright 2002 Niels Provos <provos@citi.umich.edu>
.\" * All rights reserved.
@ -23,7 +23,7 @@
.\" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" */
.Dd $Mdocdate: January 28 2009 $
.Dd $Mdocdate: September 8 2014 $
.Dt TREE 3
.Os
.Sh NAME
@ -63,13 +63,15 @@
.Nm RB_RIGHT ,
.Nm RB_PARENT ,
.Nm RB_FOREACH ,
.Nm RB_FOREACH_SAFE ,
.Nm RB_FOREACH_REVERSE ,
.Nm RB_FOREACH_REVERSE_SAFE ,
.Nm RB_INIT ,
.Nm RB_INSERT ,
.Nm RB_REMOVE
.Nd "implementations of splay and red-black trees"
.Nd implementations of splay and red-black trees
.Sh SYNOPSIS
.Fd #include <sys/tree.h>
.In sys/tree.h
.Pp
.Fn SPLAY_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP"
.Fn SPLAY_GENERATE "NAME" "TYPE" "FIELD" "CMP"
@ -130,7 +132,9 @@
.Ft "struct TYPE *"
.Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME"
.Fn RB_FOREACH "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Fn RB_FOREACH_REVERSE "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_REVERSE_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Ft void
.Fn RB_INIT "RB_HEAD *head"
.Ft "struct TYPE *"
@ -258,6 +262,11 @@ The
macro inserts the new element
.Fa elm
into the tree.
Upon success,
.Va NULL
is returned.
If a matching element already exists in the tree, the insertion is
aborted, and a pointer to the existing element is returned.
.Pp
The
.Fn SPLAY_REMOVE
@ -265,6 +274,11 @@ macro removes the element
.Fa elm
from the tree pointed by
.Fa head .
Upon success, a pointer to the removed element is returned.
.Va NULL
is returned if
.Fa elm
is not present in the tree.
.Pp
The
.Fn SPLAY_FIND
@ -405,6 +419,9 @@ macro removes the element
.Fa elm
from the tree pointed by
.Fa head .
.Fn RB_REMOVE
returns
.Fa elm .
.Pp
The
.Fn RB_FIND
@ -443,6 +460,18 @@ macros:
RB_FOREACH(np, NAME, &head)
.Ed
.Pp
The macros
.Fn RB_FOREACH_SAFE
and
.Fn RB_FOREACH_REVERSE_SAFE
traverse the tree referenced by head
in a forward or reverse direction respectively,
assigning each element in turn to np.
However, unlike their unsafe counterparts,
they permit both the removal of np
as well as freeing it from within the loop safely
without interfering with the traversal.
.Pp
The
.Fn RB_EMPTY
macro should be used to check whether a red-black tree is empty.
@ -543,22 +572,6 @@ for (var = SPLAY_MIN(NAME, &head); var != NULL; var = nxt) {
free(var);
}
.Ed
.Pp
Both
.Fn RB_INSERT
and
.Fn SPLAY_INSERT
return
.Va NULL
if the element was inserted in the tree successfully, otherwise they
return a pointer to the element with the colliding key.
.Pp
Accordingly,
.Fn RB_REMOVE
and
.Fn SPLAY_REMOVE
return the pointer to the removed element, otherwise they return
.Va NULL
to indicate an error.
.Sh AUTHORS
The author of the tree macros is Niels Provos.
The author of the tree macros is
.An Niels Provos .

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tree.h,v 1.11 2008/05/11 22:19:09 millert Exp $ */
/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@ -329,7 +329,7 @@ struct { \
} while (0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x)
#define RB_AUGMENT(x) do {} while (0)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
@ -730,9 +730,19 @@ name##_RB_MINMAX(struct name *head, int val) \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \
(x) = (y))
#define RB_FOREACH_REVERSE(x, name, head) \
for ((x) = RB_MAX(name, head); \
(x) != NULL; \
(x) = name##_RB_PREV(x))
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
for ((x) = RB_MAX(name, head); \
((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \
(x) = (y))
#endif /* _SYS_TREE_H_ */

View File

@ -2,7 +2,7 @@ dnl ###########
dnl ## SETUP ###########################################################
dnl ###########
AC_INIT([ezstream], [0.5.6],
AC_INIT([ezstream], [0.6.0],
[https://trac.xiph.org/newticket?component=ezstream])
AC_REVISION([$Id$])
AC_PREREQ([2.61])

View File

@ -1,6 +1,6 @@
.\" $Id$
.\"
.\" Copyright (c) 2009 Moritz Grimm <mdgrimm@gmx.net>
.\" Copyright (c) 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -23,7 +23,7 @@
.Sh SYNOPSIS
.Nm
.Bk -words
.Op Fl hnqVv
.Op Fl hmnqVv
.Op Fl T Ar cfg_template
.Op Ar
.Ek
@ -62,6 +62,12 @@ binary.
.It Fl h
Print a summary of available command line parameters with short descriptions
and exit.
.It Fl m
.Po
Passed to
.Nm ezstream .
.Pc
Disable all metadata updates and keep existing metadata in streams untouched.
.It Fl n
.Po
Passed to
@ -108,4 +114,4 @@ as well as example playlist and metadata scripts.
The
.Nm
script and this manual were written by
.An Moritz Grimm Aq mdgrimm@gmx.net .
.An Moritz Grimm .

View File

@ -1,6 +1,6 @@
.\" $Id$
.\"
.\" Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
.\" Copyright (c) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License version 2 as
@ -24,7 +24,7 @@
.Sh SYNOPSIS
.Nm
.Bk -words
.Op Fl hnqVv
.Op Fl hmnqVv
.Fl c Ar configfile
.Ek
.Nm
@ -52,6 +52,8 @@ Use the XML configuration in
.It Fl h
Print a summary of available command line parameters with short descriptions
and exit.
.It Fl m
Disable all metadata updates and keep existing metadata in streams untouched.
.It Fl n
Normalize metadata strings by removing excess whitespaces.
.It Fl q
@ -275,6 +277,17 @@ See the
.Sy METADATA
section for details on how metadata is handled by
.Nm .
.It Sy \&<metadata_refreshinterval\ /\&>
.Pq Optional.
Configures the time
.Pq in seconds
inbetween additional metadata updates via
.Li \&<metadata_progname/\&> .
A value of 0
.Pq zero
triggers updates as fast as possible, while a value of \&-1
.Pq minus one
or the absence of this configuration element disables this feature.
.It Sy \&<stream_once\ /\&>
Set to
.Sy 1
@ -428,7 +441,7 @@ For example, to decode Ogg Vorbis files using the
.Cm oggdec
utility:
.Pp
.Dl \&<decode\&>oggdec -R -o - \&"@T@\&"\&</decode\&>
.Dl \&<decode\&>oggdec -R -o - @T@\&</decode\&>
.It Sy \&<encode\ /\&>
Set the command to encode raw data, received from standard input, to the
specified stream format.
@ -447,7 +460,7 @@ the
.Cm oggenc
utility:
.Pp
.Dl \&<encode\&>oggenc -r -q 1.5 -t \&"@M@\&" -\&</encode\&>
.Dl \&<encode\&>oggenc -r -q 1.5 -t @M@ -\&</encode\&>
.El
.Sh SCRIPTING
The
@ -506,9 +519,17 @@ The main tool for handling metadata with
.Nm
is placeholders in decoder and encoder commands that are replaced with real
content during runtime.
The tricky part is that one of the placeholders has to be handled differently,
depending on where the metadata comes from.
This section will explain each possible scenario.
.Pp
.Em Note:
To prevent malicious shell script in metadata
.Pq such as artist and title tags
from being executed, all metadata content is automatically enclosed in single
quotes, with escaped single quote and backslash characters inbetween.
To prevent this from causing unwanted side-effects
.Pq or introducting security risk ,
placeholders
.Em must not
be quoted any further.
.Ss Metadata Placeholders
.Bl -tag -width -Ds
.It Sy @T@
@ -633,6 +654,8 @@ as well as example playlist and metadata scripts.
was written by:
.Pp
.An Ed Zaleski Aq oddsock@oddsock.org
.An Moritz Grimm Aq mdgrimm@gmx.net
.An Moritz Grimm Aq mgrimm@mrsserver.net
.Pp
This manual was written by Moritz Grimm.
.An -nosplit
This manual was written by
.An Moritz Grimm .

View File

@ -18,6 +18,11 @@
configuration must be as follows:
-->
<filename>%FILENAME%</filename>
<!--
If the generated playlist should not loop forever, set <stream_once />
to 1.
-->
<stream_once>0</stream_once>
<!--
The usual, remaining configuration statements follow. See the other
examples and the documentation for details.
@ -35,19 +40,19 @@
<encdec>
<format>FLAC</format>
<match>.flac</match>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - "@T@"</decode>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - @T@</decode>
</encdec>
<encdec>
<format>MP3</format>
<match>.mp3</match>
<decode>madplay -b 16 -R 44100 -S -o raw:- "@T@"</decode>
<decode>madplay -b 16 -R 44100 -S -o raw:- @T@</decode>
<encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode>
</encdec>
<encdec>
<format>VORBIS</format>
<match>.ogg</match>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - "@T@"</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t "@M@" -</encode>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - @T@</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</encode>
</encdec>
</reencode>
</ezstream>

View File

@ -20,6 +20,8 @@
<metadata_progname>meta.sh</metadata_progname>
<!-- Set the metadata string according to this format: -->
<metadata_format>@s@: @a@ - @t@</metadata_format>
<!-- Update metadata from meta.sh at least once every 10 seconds: -->
<metadata_refreshinterval>10</metadata_refreshinterval>
<!--
The following settings are used to describe your stream to the server.
It's up to you to make sure that the bitrate/quality/samplerate/channels

View File

@ -61,7 +61,7 @@
<!-- Support for FLAC decoding: -->
<format>FLAC</format>
<match>.flac</match>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - "@T@"</decode>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - @T@</decode>
<!-- <encode>Not supported Yet</encode> -->
</encdec>
<encdec>
@ -71,7 +71,7 @@
<format>MP3</format>
<match>.mp3</match>
<!-- Note: madplay uses host byte order for raw samples. -->
<decode>madplay -b 16 -R 44100 -S -o raw:- "@T@"</decode>
<decode>madplay -b 16 -R 44100 -S -o raw:- @T@</decode>
<encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode>
</encdec>
<encdec>
@ -80,8 +80,8 @@
-->
<format>VORBIS</format>
<match>.ogg</match>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - "@T@"</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t "@M@" -</encode>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - @T@</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</encode>
</encdec>
</reencode>
</ezstream>

View File

@ -67,12 +67,12 @@
-->
<format>THEORA</format>
<match>.avi</match>
<decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title "@M@" -o - "@T@"</decode>
<decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title @M@ -o - @T@</decode>
</encdec>
<encdec>
<format>THEORA</format>
<match>.mpg</match>
<decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title "@M@" -o - "@T@"</decode>
<decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title @M@ -o - @T@</decode>
</encdec>
</reencode>
</ezstream>

View File

@ -62,7 +62,7 @@
<!-- Support for FLAC decoding: -->
<format>FLAC</format>
<match>.flac</match>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - "@T@"</decode>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - @T@</decode>
<!-- <encode>Not supported Yet</encode> -->
</encdec>
<encdec>
@ -72,7 +72,7 @@
<format>MP3</format>
<match>.mp3</match>
<!-- Note: madplay uses host byte order for raw samples. -->
<decode>madplay -b 16 -R 44100 -S -o raw:- "@T@"</decode>
<decode>madplay -b 16 -R 44100 -S -o raw:- @T@</decode>
<encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode>
</encdec>
<encdec>
@ -81,8 +81,8 @@
-->
<format>VORBIS</format>
<match>.ogg</match>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - "@T@"</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t "@M@" -</encode>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - @T@</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</encode>
</encdec>
</reencode>
</ezstream>

View File

@ -1,3 +0,0 @@
#!/bin/sh
svn2cl --stdout -i --reparagraph --break-before-msg -o ChangeLog

View File

@ -14,9 +14,8 @@ ezstream_SOURCES = \
xalloc.c
ezstream_LDADD = @LIBOBJS@ @EZ_LIBS@
INCLUDES = @COMPAT_INCLUDES@
AM_CFLAGS = @EZ_CFLAGS@
AM_CPPFLAGS = @EZ_CPPFLAGS@
AM_CPPFLAGS = @EZ_CPPFLAGS@ @COMPAT_INCLUDES@
AM_LDFLAGS = @EZ_LDFLAGS@
EXTRA_DIST = \

View File

@ -2,7 +2,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -89,7 +89,8 @@ parseConfig(const char *fileName)
xmlNodePtr cur;
char *ls_xmlContentPtr;
int program_set, reconnect_set, shuffle_set,
streamOnce_set, svrinfopublic_set;
streamOnce_set, svrinfopublic_set,
refresh_set;
unsigned int config_error;
xmlLineNumbersDefault(1);
@ -106,14 +107,17 @@ parseConfig(const char *fileName)
return (0);
}
memset(&ezConfig, '\000', sizeof(ezConfig));
memset(&ezConfig, 0, sizeof(ezConfig));
ezConfig.metadataRefreshInterval = -1;
config_error = 0;
program_set = 0;
reconnect_set = 0;
refresh_set = 0;
shuffle_set = 0;
streamOnce_set = 0;
svrinfopublic_set = 0;
for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"url")) {
if (ezConfig.URL != NULL) {
@ -230,6 +234,27 @@ parseConfig(const char *fileName)
}
}
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"metadata_refreshinterval")) {
if (refresh_set) {
printf("%s[%ld]: Error: Cannot have multiple <metadata_refreshinterval> elements\n",
fileName, xmlGetLineNo(cur));
config_error++;
continue;
}
if (cur->xmlChildrenNode != NULL) {
const char *errstr;
ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
ezConfig.metadataRefreshInterval = (unsigned int)strtonum(ls_xmlContentPtr, -1LL, (long long)INT_MAX, &errstr);
if (errstr) {
printf("%s[%ld]: Error: In <metadata_refreshinterval>: '%s' is %s\n",
fileName, xmlGetLineNo(cur), ls_xmlContentPtr, errstr);
config_error++;
continue;
}
xmlFree(ls_xmlContentPtr);
refresh_set = 1;
}
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"playlist_program")) {
if (program_set) {
printf("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n",

View File

@ -2,7 +2,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (C) 2007, 2015 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -66,6 +66,7 @@ typedef struct tag_EZCONFIG {
int fileNameIsProgram;
int streamOnce;
unsigned int reconnectAttempts;
int metadataRefreshInterval;
} EZCONFIG;
EZCONFIG * getEZConfig(void);

View File

@ -4,7 +4,7 @@
# Convenience/wrapper script that uses ezstream to stream one or more files
# given on the command line.
# Copyright (c) 2009 Moritz Grimm <mdgrimm@gmx.net>
# Copyright (c) 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@ -21,10 +21,10 @@
_myname="$(basename $0)"
_filename_placeholder="%FILENAME%"
_opt_string="hnqT:Vv"
_opt_string="hmnqT:Vv"
print_usage()
{
echo "usage: ${_myname} [-hnqVv] [-T cfg_template] [file ...]" >&2
echo "usage: ${_myname} [-hmnqVv] [-T cfg_template] [file ...]" >&2
}
print_usage_help()
@ -32,6 +32,7 @@ print_usage_help()
cat << __EOT >&2
-h print this help and exit
-m [ezstream] disable metadata updates
-n [ezstream] normalize metadata strings
-q [ezstream] suppress STDERR output from external en-/decoders
-T template run ezstream using template for configuration
@ -45,6 +46,7 @@ See the ezstream-file.sh(1) manual for detailed information.
__EOT
}
_metadisable=""
_normalize=""
_quiet=""
_verbose=""
@ -64,6 +66,8 @@ do
print_usage_help
exit 0
;;
-m)
_metadisable="-m"; shift ;;
-n)
_normalize="-n"; shift ;;
-q)
@ -140,6 +144,6 @@ else
done
fi
${EZSTREAM} ${_normalize} ${_quiet} ${_verbose} -c "${_cfg}"
${EZSTREAM} ${_metadisable} ${_normalize} ${_quiet} ${_verbose} -c "${_cfg}"
exit $?

View File

@ -2,7 +2,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -50,6 +50,7 @@ char *__progname;
#endif /* HAVE___PROGNAME */
int nFlag;
int mFlag;
int qFlag;
int sFlag;
int vFlag;
@ -89,8 +90,8 @@ typedef struct tag_ID3Tag {
} ID3Tag;
int urlParse(const char *, char **, unsigned short *, char **);
void replaceString(const char *, char *, size_t, const char *,
const char *);
char * shellQuote(const char *);
char * replaceString(const char *, const char *, const char *);
char * buildCommandString(const char *, const char *, metadata_t *);
char * getMetadataString(const char *, metadata_t *);
metadata_t * getMetadata(const char *);
@ -196,25 +197,67 @@ urlParse(const char *url, char **hostname, unsigned short *port,
return (1);
}
void
replaceString(const char *source, char *dest, size_t size,
const char *from, const char *to)
{
const char *p1 = source;
const char *p2;
#define SHELLQUOTE_INLEN_MAX 8191UL
char *
shellQuote(const char *in)
{
char *out, *out_p;
size_t out_len;
const char *in_p;
out_len = (strlen(in) > SHELLQUOTE_INLEN_MAX)
? SHELLQUOTE_INLEN_MAX
: strlen(in);
out_len = out_len * 2 + 2;
out = xcalloc(out_len + 1, sizeof(char));
out_p = out;
in_p = in;
*out_p++ = '\'';
out_len--;
while (*in_p && out_len > 2) {
switch (*in_p) {
case '\'':
case '\\':
*out_p++ = '\\';
out_len--;
break;
default:
break;
}
*out_p++ = *in_p++;
out_len--;
}
*out_p++ = '\'';
return (out);
}
char *
replaceString(const char *source, const char *from, const char *to)
{
char *to_quoted, *dest;
size_t dest_size;
const char *p1, *p2;
to_quoted = shellQuote(to);
dest_size = strlen(source) + strlen(to_quoted) + 1;
dest = xcalloc(dest_size, sizeof(char));
p1 = source;
p2 = strstr(p1, from);
if (p2 != NULL) {
if ((unsigned int)(p2 - p1) >= size) {
printf("%s: replaceString(): Internal error: p2 - p1 >= size\n",
__progname);
abort();
}
strncat(dest, p1, (size_t)(p2 - p1));
strlcat(dest, to, size);
strlcat(dest, to_quoted, dest_size);
p1 = p2 + strlen(from);
}
strlcat(dest, p1, size);
strlcat(dest, p1, dest_size);
xfree(to_quoted);
return (dest);
}
char *
@ -226,9 +269,7 @@ buildCommandString(const char *extension, const char *fileName,
char *encoder = NULL;
char *decoder = NULL;
char *newDecoder = NULL;
size_t newDecoderLen = 0;
char *newEncoder = NULL;
size_t newEncoderLen = 0;
char *localTitle = UTF8toCHAR(metadata_get_title(mdata),
ICONV_REPLACE);
char *localArtist = UTF8toCHAR(metadata_get_artist(mdata),
@ -246,23 +287,16 @@ buildCommandString(const char *extension, const char *fileName,
xfree(decoder);
return (NULL);
}
newDecoderLen = strlen(decoder) + strlen(fileName) + 1;
newDecoder = xcalloc(newDecoderLen, sizeof(char));
replaceString(decoder, newDecoder, newDecoderLen, TRACK_PLACEHOLDER,
fileName);
newDecoder = replaceString(decoder, TRACK_PLACEHOLDER, fileName);
if (strstr(decoder, ARTIST_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newDecoder) + strlen(localArtist) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newDecoder, tmpStr, tmpLen, ARTIST_PLACEHOLDER,
localArtist);
char *tmpStr = replaceString(newDecoder, ARTIST_PLACEHOLDER,
localArtist);
xfree(newDecoder);
newDecoder = tmpStr;
}
if (strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newDecoder) + strlen(localTitle) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newDecoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
localTitle);
char *tmpStr = replaceString(newDecoder, TITLE_PLACEHOLDER,
localTitle);
xfree(newDecoder);
newDecoder = tmpStr;
}
@ -279,27 +313,20 @@ buildCommandString(const char *extension, const char *fileName,
if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) {
if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
size_t tmpLen = strlen(newDecoder) + strlen(mdataString) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newDecoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, mdataString);
char *tmpStr = replaceString(newDecoder,
METADATA_PLACEHOLDER, mdataString);
xfree(newDecoder);
xfree(mdataString);
newDecoder = tmpStr;
} else {
if (!metadataFromProgram && strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newDecoder) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newDecoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, "");
char *tmpStr = replaceString(newDecoder,
METADATA_PLACEHOLDER, "");
xfree(newDecoder);
newDecoder = tmpStr;
} else {
size_t tmpLen = strlen(newDecoder) + strlen(localMetaString) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newDecoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER,
localMetaString);
char *tmpStr = replaceString(newDecoder,
METADATA_PLACEHOLDER, localMetaString);
xfree(newDecoder);
newDecoder = tmpStr;
}
@ -325,42 +352,30 @@ buildCommandString(const char *extension, const char *fileName,
return (commandString);
}
newEncoderLen = strlen(encoder) + strlen(localArtist) + 1;
newEncoder = xcalloc(newEncoderLen, sizeof(char));
replaceString(encoder, newEncoder, newEncoderLen, ARTIST_PLACEHOLDER,
localArtist);
newEncoder = replaceString(encoder, ARTIST_PLACEHOLDER, localArtist);
if (strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newEncoder) + strlen(localTitle) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newEncoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
localTitle);
char *tmpStr = replaceString(newEncoder, TITLE_PLACEHOLDER,
localTitle);
xfree(newEncoder);
newEncoder = tmpStr;
}
if (strstr(encoder, METADATA_PLACEHOLDER) != NULL) {
if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
size_t tmpLen = strlen(newEncoder) + strlen(mdataString) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newEncoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, mdataString);
char *tmpStr = replaceString(newEncoder,
METADATA_PLACEHOLDER, mdataString);
xfree(newEncoder);
xfree(mdataString);
newEncoder = tmpStr;
} else {
if (!metadataFromProgram && strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newEncoder) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newEncoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, "");
char *tmpStr = replaceString(newEncoder,
METADATA_PLACEHOLDER, "");
xfree(newEncoder);
newEncoder = tmpStr;
} else {
size_t tmpLen = strlen(newEncoder) + strlen(localMetaString) + 1;
char *tmpStr = xcalloc(tmpLen, sizeof(char));
replaceString(newEncoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER,
localMetaString);
char *tmpStr = replaceString(newEncoder,
METADATA_PLACEHOLDER, localMetaString);
xfree(newEncoder);
newEncoder = tmpStr;
}
@ -388,7 +403,6 @@ char *
getMetadataString(const char *format, metadata_t *mdata)
{
char *tmp, *str;
size_t len;
if (mdata == NULL) {
printf("%s: getMetadataString(): Internal error: NULL metadata_t\n",
@ -402,34 +416,26 @@ getMetadataString(const char *format, metadata_t *mdata)
str = xstrdup(format);
if (strstr(format, ARTIST_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_artist(mdata)) + 1;
tmp = xcalloc(len, sizeof(char));
replaceString(str, tmp, len, ARTIST_PLACEHOLDER,
metadata_get_artist(mdata));
tmp = replaceString(str, ARTIST_PLACEHOLDER,
metadata_get_artist(mdata));
xfree(str);
str = tmp;
}
if (strstr(format, TITLE_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_title(mdata)) + 1;
tmp = xcalloc(len, sizeof(char));
replaceString(str, tmp, len, TITLE_PLACEHOLDER,
metadata_get_title(mdata));
tmp = replaceString(str, TITLE_PLACEHOLDER,
metadata_get_title(mdata));
xfree(str);
str = tmp;
}
if (strstr(format, STRING_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_string(mdata)) + 1;
tmp = xcalloc(len, sizeof(char));
replaceString(str, tmp, len, STRING_PLACEHOLDER,
metadata_get_string(mdata));
tmp = replaceString(str, STRING_PLACEHOLDER,
metadata_get_string(mdata));
xfree(str);
str = tmp;
}
if (strstr(format, TRACK_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_filename(mdata)) + 1;
tmp = xcalloc(len, sizeof(char));
replaceString(str, tmp, len, TRACK_PLACEHOLDER,
metadata_get_filename(mdata));
tmp = replaceString(str, TRACK_PLACEHOLDER,
metadata_get_filename(mdata));
xfree(str);
str = tmp;
}
@ -477,6 +483,9 @@ setMetadata(shout_t *shout, metadata_t *mdata, char **mdata_copy)
abort();
}
if (mFlag)
return (SHOUTERR_SUCCESS);
if (mdata == NULL)
return 1;
@ -750,6 +759,7 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
int ret;
double kbps = -1.0;
struct timeval timeStamp, *startTime = tv;
struct timeval callTime, currentTime;
if (startTime == NULL) {
printf("%s: sendStream(): Internal error: startTime is NULL\n",
@ -757,6 +767,8 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
abort();
}
ez_gettimeofday((void *)&callTime);
timeStamp.tv_sec = startTime->tv_sec;
timeStamp.tv_usec = startTime->tv_usec;
@ -795,7 +807,15 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
ret = STREAM_SKIP;
break;
}
if (queryMetadata) {
ez_gettimeofday((void *)&currentTime);
if (queryMetadata ||
(pezConfig->metadataRefreshInterval != -1
&& (currentTime.tv_sec - callTime.tv_sec
>= pezConfig->metadataRefreshInterval)
)
) {
queryMetadata = 0;
if (metadataFromProgram) {
ret = STREAM_UPDMDATA;
@ -805,8 +825,7 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
total += bytes_read;
if (qFlag && vFlag) {
struct timeval tval;
double oldTime, newTime;
double oldTime, newTime;
if (!isStdin && playlistMode) {
if (pezConfig->fileNameIsProgram) {
@ -822,20 +841,22 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
oldTime = (double)timeStamp.tv_sec
+ (double)timeStamp.tv_usec / 1000000.0;
ez_gettimeofday((void *)&tval);
newTime = (double)tval.tv_sec
+ (double)tval.tv_usec / 1000000.0;
newTime = (double)currentTime.tv_sec
+ (double)currentTime.tv_usec / 1000000.0;
if (songLenStr == NULL)
printf(" [ %s]",
getTimeString(tval.tv_sec - startTime->tv_sec));
getTimeString(currentTime.tv_sec -
startTime->tv_sec));
else
printf(" [ %s/%s]",
getTimeString(tval.tv_sec - startTime->tv_sec),
getTimeString(currentTime.tv_sec -
startTime->tv_sec),
songLenStr);
if (newTime - oldTime >= 1.0) {
kbps = (((double)(total - oldTotal) / (newTime - oldTime)) * 8.0) / 1000.0;
timeStamp.tv_sec = tval.tv_sec;
timeStamp.tv_usec = tval.tv_usec;
kbps = (((double)(total - oldTotal)
/ (newTime - oldTime)) * 8.0) / 1000.0;
timeStamp.tv_sec = currentTime.tv_sec;
timeStamp.tv_usec = currentTime.tv_usec;
oldTotal = total;
}
if (kbps < 0)
@ -936,6 +957,8 @@ streamFile(shout_t *shout, const char *fileName)
}
if (ret == STREAM_UPDMDATA || queryMetadata) {
queryMetadata = 0;
if (mFlag)
continue;
if (metadataFromProgram) {
char *mdataStr = NULL;
metadata_t *prog_mdata;
@ -954,8 +977,9 @@ streamFile(shout_t *shout, const char *fileName)
continue;
}
metadata_free(&prog_mdata);
printf("%s: New metadata: ``%s''\n",
__progname, mdataStr);
if (vFlag > 1)
printf("%s: New metadata: ``%s''\n",
__progname, mdataStr);
xfree(mdataStr);
}
}
@ -969,7 +993,7 @@ streamFile(shout_t *shout, const char *fileName)
if (popenFlag)
pclose(filepstream);
else
else if (!isStdin)
fclose(filepstream);
if (songLenStr != NULL)
@ -1073,7 +1097,7 @@ ez_shutdown(int exitval)
void
usage(void)
{
printf("usage: %s [-hnqVv] -c configfile\n", __progname);
printf("usage: %s [-hmnqVv] -c configfile\n", __progname);
printf(" %s -s [playlist]\n", __progname);
}
@ -1083,6 +1107,7 @@ usageHelp(void)
printf("\n");
printf(" -c configfile use XML configuration in configfile (mandatory)\n");
printf(" -h display this additional help and exit\n");
printf(" -m disable metadata updates\n");
printf(" -n normalize metadata strings\n");
printf(" -q suppress STDERR output from external en-/decoders\n");
printf(" -s [playlist] read lines from playlist (or STDIN), shuffle and print them to\n");
@ -1120,11 +1145,12 @@ main(int argc, char *argv[])
__progname = getProgname(argv[0]);
pezConfig = getEZConfig();
mFlag = 0;
nFlag = 0;
qFlag = 0;
vFlag = 0;
while ((c = local_getopt(argc, argv, "c:hnqsVv")) != -1) {
while ((c = local_getopt(argc, argv, "c:hmnqsVv")) != -1) {
switch (c) {
case 'c':
if (configFile != NULL) {
@ -1138,6 +1164,9 @@ main(int argc, char *argv[])
usage();
usageHelp();
return (ez_shutdown(0));
case 'm':
mFlag = 1;
break;
case 'n':
nFlag = 1;
break;
@ -1316,7 +1345,6 @@ main(int argc, char *argv[])
printf("%s: Using program '%s' to get filenames for streaming\n",
__progname, pezConfig->fileName);
ret = 1;
do {
if (playlistMode) {
ret = streamPlaylist(shout,

View File

@ -1,6 +1,6 @@
/* $Id$ */
/*
* Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (c) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -27,9 +27,8 @@
#endif /* HAVE_SYS_TYPES_H */
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else /* HAVE_SYS_TIME_H */
# include <time.h>
#endif /* HAVE_SYS_TIME_H */
#include <time.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */

View File

@ -1,6 +1,6 @@
/* $Id$ */
/*
* Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (c) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
/* $Id$ */
/*
* Copyright (c) 2007 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (c) 2007 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
/* $Id$ */
/*
* Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (c) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
/* $Id$ */
/*
* Copyright (c) 2007 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (c) 2007 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View File

@ -2,7 +2,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (C) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as

View File

@ -2,7 +2,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (C) 2007 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as

View File

@ -1,6 +1,6 @@
/* $Id$ */
/*
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (C) 2007 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View File

@ -7,7 +7,7 @@
* and ensures that out-of-memory issues always cause the
* application to exit.
*
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net>
* Copyright (C) 2007 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View File

@ -67,13 +67,13 @@ A few useful features are missing in the Windows version of ezstream:
Ezstream uses:
* zlib (http://www.zlib.net/, BSD-like license)
* libiconv (http://www.gnu.org/software/libiconv/, LGPL)
* libiconv (https://www.gnu.org/software/libiconv/, LGPL)
* libxml2 (http://xmlsoft.org/, BSD-like license)
* libogg, libvorbis, libvorbisfile (http://www.vorbis.com/, BSD-like license)
* libFLAC (http://flac.sourceforge.net/, BSD-like license)
* libFLAC (https://xiph.org/flac/, BSD-like license)
* libtheora (http://www.theora.org/, BSD-like license)
* libshout (http://www.icecast.org, LGPL)
* TagLib (http://ktown.kde.org/~wheeler/taglib.html, LGPL)
* TagLib (https://taglib.github.io/, LGPL)
These libraries are statically linked into the ezstream.exe file.

View File

@ -1,7 +1,7 @@
#ifndef __WIN32_CONFIG_H__
#define __WIN32_CONFIG_H__
#define PACKAGE_STRING "ezstream 0.5.6"
#define PACKAGE_STRING "ezstream 0.6.0"
#define HAVE_SYS_TYPES_H 1
#define HAVE_SYS_STAT_H 1