[xiph-commits] r14821 - in icecast/branches/kh/icecast: . src
karl at svn.xiph.org
karl at svn.xiph.org
Wed Apr 30 19:28:21 PDT 2008
Author: karl
Date: 2008-04-30 19:28:21 -0700 (Wed, 30 Apr 2008)
New Revision: 14821
Added:
icecast/branches/kh/icecast/src/format_kate.c
icecast/branches/kh/icecast/src/format_kate.h
icecast/branches/kh/icecast/src/format_skeleton.c
icecast/branches/kh/icecast/src/format_skeleton.h
Modified:
icecast/branches/kh/icecast/NEWS
icecast/branches/kh/icecast/configure.in
icecast/branches/kh/icecast/src/Makefile.am
icecast/branches/kh/icecast/src/admin.c
icecast/branches/kh/icecast/src/cfgfile.c
icecast/branches/kh/icecast/src/format.c
icecast/branches/kh/icecast/src/format_ogg.c
icecast/branches/kh/icecast/src/main.c
icecast/branches/kh/icecast/src/source.c
icecast/branches/kh/icecast/src/stats.c
icecast/branches/kh/icecast/src/stats.h
icecast/branches/kh/icecast/src/yp.c
Log:
kh34. sync up with trunk, kate/skeleton merge, small yp tweaks for error
cases and some cleanups for stats
Modified: icecast/branches/kh/icecast/NEWS
===================================================================
--- icecast/branches/kh/icecast/NEWS 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/NEWS 2008-05-01 02:28:21 UTC (rev 14821)
@@ -7,20 +7,35 @@
. When max-listeners reached, a HTTP 302 code can be sent to redirect
clients to alternative slave hosts.
. authenticated relays, those that match the relay user/pass, bypass the
- max-listener/bandwidth check
+ max-listener/bandwidth check. slaves can use a different auth to listeners
. mount can filter out theora content, useful for defining a local relay
of a theora+vorbis stream to have a vorbis only stream from the same source.
-. stream-auth/handlers option for url authenticator.
+. stream-auth/handlers options for url authenticator.
any extra tags are show in the conf/icecast.xml.dist file
+2.3-kh34
+. Added Kate/Skeleton codec handling within Ogg streams. patch by ogg.k.ogg.k
+. small changes for stream directory handling, mostly for error cases.
+. added /admin/reset?mount=/mountpoint&setting=x to reset stats for that mountpoint.
+ without setting= all resetable stats are reset. x can specify peak,read or send
+ or a combination of them (comma deliminated)
+. /admin/streamlist.txt uses the same routine as /admin/streams so does not have
+ a limit on how much is sent back.
+. updated win32 code, windows service should be ok again. service name now
+ includes version to help multiple installs but windows may require a reboot
+ between removing a service and installing that same service again.
+. fix possible crash on reload of xml with bad tags
+. small update of web pages
+. added per-mount stat for total mbytes sent
+
2.3-kh33
. master/slave update.
- slave mode only issues a streamlist.txt request if the /admin/slaves request
- fails. /admin/slaves also acts as an mountpoint for the slave relays by
+ slave mode only issues a streamlist.txt request if the /admin/streams request
+ fails. /admin/streams also acts as an mountpoint for the slave relays by
passing a mount= arg and auth.
- You can now define a <mount> for /admin/slaves to define how slave
+ You can now define a <mount> for /admin/streams to define how slave
authentication is done eg url (listener_add) or htpasswd.
Once authenticated, the slave can bypass any limits like max listeners etc.
The slave also allows for defining a <master> tag block instead of <master-*>
Modified: icecast/branches/kh/icecast/configure.in
===================================================================
--- icecast/branches/kh/icecast/configure.in 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/configure.in 2008-05-01 02:28:21 UTC (rev 14821)
@@ -1,4 +1,4 @@
-AC_INIT([Icecast], [2.3-kh33], [karl at xiph.org])
+AC_INIT([Icecast], [2.3-kh34], [karl at xiph.org])
AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(src/main.c)
@@ -82,6 +82,19 @@
[ AC_MSG_WARN([Speex support disabled!])
])
+AC_CHECK_LIB(kate, kate_decode_init,[have_kate=yes],[have_kate=no], -logg)
+if test "x$have_kate" == "xyes"
+then
+ AC_CHECK_LIB(oggkate, kate_ogg_decode_headerin,[have_kate=yes],[have_kate=no],-lkate -logg)
+ if test "x$have_kate" == "xyes"
+ then
+ KATE_LIBS="-loggkate -lkate -logg"
+ AC_DEFINE([HAVE_KATE],[1],[Define if you have libkate])
+ fi
+fi
+dnl we still use format_kate as it doesn't need libkate to work
+#ICECAST_OPTIONAL="$ICECAST_OPTIONAL format_kate.o"
+
ACX_PTHREAD(, AC_MSG_ERROR([POSIX threads missing]))
XIPH_VAR_APPEND([XIPH_CFLAGS],[$PTHREAD_CFLAGS])
XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$PTHREAD_CPPFLAGS])
@@ -90,6 +103,7 @@
XIPH_PATH_CURL([
AC_CHECK_DECL([CURLOPT_NOSIGNAL],
[ AC_DEFINE([HAVE_AUTH_URL], 1, [Define to compile in auth URL support code])
+ AC_CHECK_FUNCS([curl_global_init])
ICECAST_OPTIONAL="$ICECAST_OPTIONAL auth_url.o"
enable_curl="yes"
XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$CURL_CFLAGS])
@@ -137,6 +151,8 @@
AC_SUBST(CFLAGS)
AC_SUBST(PROFILE)
AC_SUBST(ICECAST_OPTIONAL)
+AC_SUBST(HAVE_KATE)
+AC_SUBST(KATE_LIBS)
AC_OUTPUT([Makefile conf/Makefile debian/Makefile src/Makefile src/avl/Makefile
src/httpp/Makefile src/thread/Makefile src/log/Makefile
Modified: icecast/branches/kh/icecast/src/Makefile.am
===================================================================
--- icecast/branches/kh/icecast/src/Makefile.am 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/Makefile.am 2008-05-01 02:28:21 UTC (rev 14821)
@@ -10,25 +10,26 @@
global.h util.h slave.h source.h stats.h refbuf.h client.h \
compat.h fserve.h xslt.h yp.h event.h md5.h \
auth.h auth_htpasswd.h auth_cmd.h auth_url.h \
+ fnmatch_loop.c \
format.h format_ogg.h format_mp3.h \
format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \
- fnmatch_loop.c
+ format_kate.h format_skeleton.h
icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \
util.c slave.c source.c stats.c refbuf.c client.c \
xslt.c fserve.c event.c admin.c md5.c \
format.c format_ogg.c format_mp3.c format_midi.c format_flac.c \
- auth.c auth_htpasswd.c
+ auth.c auth_htpasswd.c format_kate.c format_skeleton.c
EXTRA_icecast_SOURCES = yp.c \
auth_url.c auth_cmd.c \
format_vorbis.c format_theora.c format_speex.c fnmatch.c
icecast_DEPENDENCIES = @ICECAST_OPTIONAL@ net/libicenet.la thread/libicethread.la \
httpp/libicehttpp.la log/libicelog.la avl/libiceavl.la timing/libicetiming.la
-icecast_LDADD = $(icecast_DEPENDENCIES) @XIPH_LIBS@
+icecast_LDADD = $(icecast_DEPENDENCIES) @XIPH_LIBS@ @KATE_LIBS@
AM_CFLAGS = @XIPH_CFLAGS@
AM_CPPFLAGS = @XIPH_CPPFLAGS@
-AM_LDFLAGS = @XIPH_LDFLAGS@
+AM_LDFLAGS = @XIPH_LDFLAGS@ @KATE_LIBS@
debug:
Modified: icecast/branches/kh/icecast/src/admin.c
===================================================================
--- icecast/branches/kh/icecast/src/admin.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/admin.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -54,6 +54,7 @@
static void command_stats_mount (client_t *client, source_t *source, int response);
static void command_kill_client(client_t *client, source_t *source,
int response);
+static void command_reset_stats (client_t *client, source_t *source, int response);
static void command_manageauth(client_t *client, source_t *source,
int response);
static void command_buildm3u(client_t *client, const char *mount);
@@ -113,6 +114,7 @@
{ "stats", RAW, { command_stats_mount } },
{ "manageauth", RAW, { command_manageauth } },
{ "admin.cgi", RAW, { command_shoutcast_metadata } },
+ { "resetstats", XSLT, { command_reset_stats } },
{ "metadata.xsl", XSLT, { command_metadata } },
{ "listclients.xsl", XSLT, { command_show_listeners } },
{ "updatemetadata.xsl", XSLT, { command_updatemetadata } },
@@ -665,6 +667,46 @@
}
+static void command_reset_stats (client_t *client, source_t *source, int response)
+{
+ const char *msg = "Failed to reset values";
+ const char *name = httpp_get_query_param (client->parser, "setting");
+ int all = 0, ok = 0;
+ xmlDocPtr doc;
+ xmlNodePtr node;
+
+ if (name == NULL)
+ all = 1;
+ if (all || strstr (name, "peak"))
+ {
+ source->peak_listeners = source->listeners;
+ source->prev_listeners = source->peak_listeners+1;
+ ok = 1;
+ }
+ if (all || strstr (name, "read"))
+ if (source->format)
+ {
+ source->format->read_bytes = 0;
+ ok = 1;
+ }
+ if (all || strstr (name, "sent"))
+ if (source->format)
+ {
+ source->format->sent_bytes = 0;
+ ok = 1;
+ }
+
+ if (ok)
+ msg = "have reset settings";
+ doc = xmlNewDoc(XMLSTR("1.0"));
+ node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
+ xmlDocSetRootElement(doc, node);
+ xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(msg));
+ xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
+ admin_send_response(doc, client, response, "response.xsl");
+ xmlFreeDoc(doc);
+}
+
static void command_show_listeners(client_t *client, source_t *source,
int response)
{
@@ -1101,23 +1143,17 @@
if (response == TEXT)
{
- char *buf;
- int remaining = PER_CLIENT_REFBUF_SIZE;
- int ret;
-
redirector_update (client);
- buf = client->refbuf->data;
- ret = snprintf (buf, remaining,
+ snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
+ client->refbuf->len = strlen (client->refbuf->data);
client->respcode = 200;
if (strcmp (httpp_getvar (client->parser, HTTPP_VAR_URI), "/admin/streams") == 0)
- client->refbuf->next = stats_get_streams ();
+ client->refbuf->next = stats_get_streams (1);
else
- stats_get_streamlist (buf+ret, remaining-ret);
-
- client->refbuf->len = strlen (client->refbuf->data);
+ client->refbuf->next = stats_get_streams (0);
fserve_add_client (client, NULL);
}
else
Modified: icecast/branches/kh/icecast/src/cfgfile.c
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/cfgfile.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -174,7 +174,7 @@
ret = argp->retrieve (node, argp->storage);
if (ret > 0)
{
- xmlParserWarning(stderr, "skipping element \"%s\" parsing \"%s\"\n", node->name, parent->name);
+ xmlParserWarning (NULL, "skipping element \"%s\" parsing \"%s\"\n", node->name, parent->name);
ret = 0;
}
break;
Modified: icecast/branches/kh/icecast/src/format.c
===================================================================
--- icecast/branches/kh/icecast/src/format.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/format.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -53,6 +53,10 @@
return FORMAT_TYPE_OGG; /* Backwards compatibility */
else if(strcmp(contenttype, "application/ogg") == 0)
return FORMAT_TYPE_OGG; /* Now blessed by IANA */
+ else if(strcmp(contenttype, "audio/ogg") == 0)
+ return FORMAT_TYPE_OGG;
+ else if(strcmp(contenttype, "video/ogg") == 0)
+ return FORMAT_TYPE_OGG;
else
/* We default to the Generic format handler, which
can handle many more formats than just mp3 */
Added: icecast/branches/kh/icecast/src/format_kate.c
===================================================================
--- icecast/branches/kh/icecast/src/format_kate.c (rev 0)
+++ icecast/branches/kh/icecast/src/format_kate.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -0,0 +1,232 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+
+/* Ogg codec handler for kate logical streams */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+#ifdef HAVE_KATE
+#include <kate/oggkate.h>
+#endif
+
+typedef struct source_tag source_t;
+
+#include "refbuf.h"
+#include "format_ogg.h"
+#include "format_kate.h"
+#include "client.h"
+#include "stats.h"
+
+#define CATMODULE "format-kate"
+#include "logging.h"
+
+
+typedef struct _kate_codec_tag
+{
+ int headers_done;
+#ifdef HAVE_KATE
+ kate_info ki;
+ kate_comment kc;
+#endif
+ int num_headers;
+ int granule_shift;
+ ogg_int64_t last_iframe;
+ ogg_int64_t prev_granulepos;
+} kate_codec_t;
+
+
+static void kate_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec)
+{
+ kate_codec_t *kate = codec->specific;
+
+ DEBUG0 ("freeing kate codec");
+ /* TODO: should i replace with something or just remove
+ stats_event (ogg_info->mount, "video_bitrate", NULL);
+ stats_event (ogg_info->mount, "video_quality", NULL);
+ stats_event (ogg_info->mount, "frame_rate", NULL);
+ stats_event (ogg_info->mount, "frame_size", NULL);
+ */
+#ifdef HAVE_KATE
+ kate_info_clear (&kate->ki);
+ kate_comment_clear (&kate->kc);
+#endif
+ ogg_stream_clear (&codec->os);
+ free (kate);
+ free (codec);
+}
+
+
+/* kate pages are not rebuilt, so here we just for headers and then
+ * pass them straight through to the the queue
+ */
+static refbuf_t *process_kate_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page)
+{
+ kate_codec_t *kate = codec->specific;
+ ogg_packet packet;
+ int header_page = 0;
+ refbuf_t *refbuf = NULL;
+ ogg_int64_t granulepos;
+
+ if (ogg_stream_pagein (&codec->os, page) < 0)
+ {
+ ogg_info->error = 1;
+ return NULL;
+ }
+ granulepos = ogg_page_granulepos (page);
+
+ while (ogg_stream_packetout (&codec->os, &packet) > 0)
+ {
+ if (!kate->headers_done)
+ {
+#ifdef HAVE_KATE
+ int ret = kate_ogg_decode_headerin (&kate->ki, &kate->kc, &packet);
+ if (ret < 0)
+ {
+ ogg_info->error = 1;
+ WARN0 ("problem with kate header");
+ return NULL;
+ }
+ header_page = 1;
+ kate->num_headers = kate->ki.num_headers;
+ codec->headers++;
+ if (ret > 0)
+ {
+ kate->headers_done = 1;
+ /* TODO: what to replace this with ?
+ ogg_info->bitrate += theora->ti.target_bitrate;
+ stats_event_args (ogg_info->mount, "video_bitrate", "%ld",
+ (long)theora->ti.target_bitrate);
+ stats_event_args (ogg_info->mount, "video_quality", "%ld",
+ (long)theora->ti.quality);
+ stats_event_args (ogg_info->mount, "frame_size", "%ld x %ld",
+ (long)theora->ti.frame_width,
+ (long)theora->ti.frame_height);
+ stats_event_args (ogg_info->mount, "frame_rate", "%.2f",
+ (float)theora->ti.fps_numerator/theora->ti.fps_denominator);
+ */
+ }
+ continue;
+#else
+ header_page = (packet.bytes>0 && (packet.packet[0]&0x80));
+ if (!header_page)
+ break;
+ codec->headers++;
+ if (packet.packet[0]==0x80)
+ {
+ if (packet.bytes<64) return NULL;
+ /* we peek for the number of headers to expect */
+ kate->num_headers = packet.packet[11];
+ }
+ continue;
+#endif
+ }
+
+ if (codec->headers < kate->num_headers)
+ {
+ ogg_info->error = 1;
+ ERROR0 ("Not enough header packets");
+ return NULL;
+ }
+ }
+ if (header_page)
+ {
+ format_ogg_attach_header (codec, page);
+ return NULL;
+ }
+
+ refbuf = make_refbuf_with_page (codec, page);
+ /* DEBUG3 ("refbuf %p has pageno %ld, %llu", refbuf, ogg_page_pageno (page), (uint64_t)granulepos); */
+
+ if (codec->possible_start)
+ {
+ /* we don't bother trying to know where we can start, we'll just
+ start whenever we have to, video's more important and in the majority
+ of the cases it's ok if we lose an event we're seeking in the middle
+ of, as we won't have display artifacts as we'd have with video */
+ codec->possible_start->sync_point = 1;
+ refbuf_release (codec->possible_start);
+ codec->possible_start = NULL;
+ }
+ if (granulepos != kate->prev_granulepos || granulepos == 0)
+ {
+ if (codec->possible_start)
+ refbuf_release (codec->possible_start);
+ refbuf_addref (refbuf);
+ codec->possible_start = refbuf;
+ }
+ kate->prev_granulepos = granulepos;
+
+ return refbuf;
+}
+
+
+/* Check if specified BOS page is the start of a kate stream and
+ * if so, create a codec structure for handling it
+ */
+ogg_codec_t *initial_kate_page (format_plugin_t *plugin, ogg_page *page)
+{
+ ogg_state_t *ogg_info = plugin->_state;
+ ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+ ogg_packet packet;
+
+ kate_codec_t *kate_codec = calloc (1, sizeof (kate_codec_t));
+
+ ogg_stream_init (&codec->os, ogg_page_serialno (page));
+ ogg_stream_pagein (&codec->os, page);
+
+#ifdef HAVE_KATE
+ kate_info_init (&kate_codec->ki);
+ kate_comment_init (&kate_codec->kc);
+#endif
+
+ ogg_stream_packetout (&codec->os, &packet);
+
+ DEBUG0("checking for kate codec");
+#ifdef HAVE_KATE
+ if (kate_ogg_decode_headerin (&kate_codec->ki, &kate_codec->kc, &packet) < 0)
+ {
+ kate_info_clear (&kate_codec->ki);
+ kate_comment_clear (&kate_codec->kc);
+ ogg_stream_clear (&codec->os);
+ free (kate_codec);
+ free (codec);
+ return NULL;
+ }
+#else
+ /* we don't have libkate, so we examine the packet magic by hand */
+ if ((packet.bytes<9) || memcmp(packet.packet, "\x80kate\0\0\0\0", 9))
+ {
+ ogg_stream_clear (&codec->os);
+ free (kate_codec);
+ free (codec);
+ return NULL;
+ }
+#endif
+
+ INFO0 ("seen initial kate header");
+ codec->specific = kate_codec;
+ codec->process_page = process_kate_page;
+ codec->codec_free = kate_codec_free;
+ codec->headers = 1;
+ codec->name = "Kate";
+
+ format_ogg_attach_header (codec, page);
+ ogg_info->codec_sync = codec;
+ return codec;
+}
+
Added: icecast/branches/kh/icecast/src/format_kate.h
===================================================================
--- icecast/branches/kh/icecast/src/format_kate.h (rev 0)
+++ icecast/branches/kh/icecast/src/format_kate.h 2008-05-01 02:28:21 UTC (rev 14821)
@@ -0,0 +1,21 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+
+#ifndef __FORMAT_KATE_H
+#define __FORMAT_KATE_H
+
+#include "format_ogg.h"
+
+ogg_codec_t *initial_kate_page (format_plugin_t *plugin, ogg_page *page);
+
+#endif /* __FORMAT_KATE_H */
Modified: icecast/branches/kh/icecast/src/format_ogg.c
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/format_ogg.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -42,6 +42,8 @@
#endif
#include "format_midi.h"
#include "format_flac.h"
+#include "format_kate.h"
+#include "format_skeleton.h"
#define CATMODULE "format-ogg"
#include "logging.h"
@@ -177,7 +179,9 @@
plugin->free_plugin = format_ogg_free_plugin;
plugin->set_tag = NULL;
plugin->apply_settings = apply_ogg_settings;
- plugin->contenttype = "application/ogg";
+ if (strcmp (httpp_getvar (source->parser, "content-type"), "application/x-ogg") == 0)
+ httpp_setvar (source->parser, "content-type", "application/ogg");
+ plugin->contenttype = httpp_getvar (source->parser, "content-type");;
ogg_sync_init (&state->oy);
@@ -268,6 +272,12 @@
if (codec)
break;
#endif
+ codec = initial_kate_page (plugin, page);
+ if (codec)
+ break;
+ codec = initial_skeleton_page (plugin, page);
+ if (codec)
+ break;
/* any others */
ERROR0 ("Seen BOS page with unknown type");
Added: icecast/branches/kh/icecast/src/format_skeleton.c
===================================================================
--- icecast/branches/kh/icecast/src/format_skeleton.c (rev 0)
+++ icecast/branches/kh/icecast/src/format_skeleton.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -0,0 +1,101 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+
+/* Ogg codec handler for skeleton logical streams */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+
+typedef struct source_tag source_t;
+
+#include "refbuf.h"
+#include "format_ogg.h"
+#include "format_skeleton.h"
+#include "client.h"
+#include "stats.h"
+
+#define CATMODULE "format-skeleton"
+#include "logging.h"
+
+
+static void skeleton_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec)
+{
+ DEBUG0 ("freeing skeleton codec");
+ ogg_stream_clear (&codec->os);
+ free (codec);
+}
+
+
+/* skeleton pages are not rebuilt, so here we just for headers and then
+ * pass them straight through to the the queue
+ */
+static refbuf_t *process_skeleton_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page)
+{
+ ogg_packet packet;
+
+ if (ogg_stream_pagein (&codec->os, page) < 0)
+ {
+ ogg_info->error = 1;
+ return NULL;
+ }
+
+ while (ogg_stream_packetout (&codec->os, &packet) > 0)
+ {
+ codec->headers++;
+ }
+
+ /* all skeleon packets are headers */
+ format_ogg_attach_header (codec, page);
+ return NULL;
+}
+
+
+/* Check if specified BOS page is the start of a skeleton stream and
+ * if so, create a codec structure for handling it
+ */
+ogg_codec_t *initial_skeleton_page (format_plugin_t *plugin, ogg_page *page)
+{
+ ogg_state_t *ogg_info = plugin->_state;
+ ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+ ogg_packet packet;
+
+ ogg_stream_init (&codec->os, ogg_page_serialno (page));
+ ogg_stream_pagein (&codec->os, page);
+
+ ogg_stream_packetout (&codec->os, &packet);
+
+ DEBUG0("checking for skeleton codec");
+
+ if ((packet.bytes<8) || memcmp(packet.packet, "fishead\0", 8))
+ {
+ ogg_stream_clear (&codec->os);
+ free (codec);
+ return NULL;
+ }
+
+ INFO0 ("seen initial skeleton header");
+ codec->process_page = process_skeleton_page;
+ codec->codec_free = skeleton_codec_free;
+ codec->headers = 1;
+ codec->name = "Skeleton";
+
+ format_ogg_attach_header (codec, page);
+ ogg_info->codec_sync = codec;
+ return codec;
+}
+
Added: icecast/branches/kh/icecast/src/format_skeleton.h
===================================================================
--- icecast/branches/kh/icecast/src/format_skeleton.h (rev 0)
+++ icecast/branches/kh/icecast/src/format_skeleton.h 2008-05-01 02:28:21 UTC (rev 14821)
@@ -0,0 +1,21 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+
+#ifndef __FORMAT_SKELETON_H
+#define __FORMAT_SKELETON_H
+
+#include "format_ogg.h"
+
+ogg_codec_t *initial_skeleton_page (format_plugin_t *plugin, ogg_page *page);
+
+#endif /* __FORMAT_SKELETON_H */
Modified: icecast/branches/kh/icecast/src/main.c
===================================================================
--- icecast/branches/kh/icecast/src/main.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/main.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -104,11 +104,16 @@
connection_initialize();
global_initialize();
refbuf_initialize();
+
+ stats_initialize();
+ fserve_initialize();
#if !defined(WIN32) || defined(WIN32_SERVICE)
/* win32 GUI needs to do the initialise before here */
xslt_initialize();
+#ifdef HAVE_CURL_GLOBAL_INIT
curl_global_init (CURL_GLOBAL_ALL);
#endif
+#endif
}
static void _shutdown_subsystems(void)
@@ -415,7 +420,6 @@
ret = config_initial_parse_file(filename);
config_release_config();
if (ret < 0) {
- memset(pbuf, '\000', sizeof(pbuf));
snprintf(pbuf, sizeof(pbuf)-1,
"FATAL: error parsing config file (%s)", filename);
_fatal_error(pbuf);
@@ -453,9 +457,6 @@
_ch_root_uid_setup(); /* Change user id and root if requested/possible */
- stats_initialize(); /* We have to do this later on because of threading */
- fserve_initialize(); /* This too */
-
#ifdef CHUID
/* We'll only have getuid() if we also have setuid(), it's reasonable to
* assume */
Modified: icecast/branches/kh/icecast/src/source.c
===================================================================
--- icecast/branches/kh/icecast/src/source.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/source.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -434,9 +434,6 @@
unsigned long kbytes_read = source->bytes_read_since_update/1024;
source->format->sent_bytes += kbytes_sent*1024;
- source->bytes_sent_since_update %= 1024;
- source->bytes_read_since_update %= 1024;
-
stats_event_args (source->mount, "outgoing_bitrate", "%ld",
(8 * rate_avg (source->format->out_bitrate))/1000);
stats_event_args (source->mount, "incoming_bitrate", "%ld", incoming_rate/1000);
@@ -444,12 +441,17 @@
"%"PRIu64, source->format->read_bytes);
stats_event_args (source->mount, "total_bytes_sent",
"%"PRIu64, source->format->sent_bytes);
+ stats_event_args (source->mount, "total_mbytes_sent",
+ "%"PRIu64, source->format->sent_bytes/(1024*1024));
if (source->client)
stats_event_args (source->mount, "connected", "%"PRIu64,
(uint64_t)(global.time - source->client->con->con_time));
stats_event_add (NULL, "stream_kbytes_sent", kbytes_sent);
stats_event_add (NULL, "stream_kbytes_read", kbytes_read);
+ source->bytes_sent_since_update %= 1024;
+ source->bytes_read_since_update %= 1024;
+
if (source->running && source->limit_rate)
{
if (incoming_rate >= source->limit_rate)
@@ -1058,6 +1060,8 @@
INFO2 ("Applying mount information for \"%s\" from \"%s\"",
source->mount, mountinfo->mountname);
+ stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
+
/* if a setting is available in the mount details then use it, else
* check the parser details. */
@@ -1118,7 +1122,7 @@
/* stream description */
if (mountinfo && mountinfo->stream_description)
- str = mountinfo->stream_description;
+ stats_event (source->mount, "server_description", mountinfo->stream_description);
else
{
do {
@@ -1128,15 +1132,14 @@
if (str) break;
str = httpp_getvar (parser, "x-audiocast-description");
if (str) break;
- str = "Unspecified description";
} while (0);
+ if (str && source->format)
+ stats_event_conv (source->mount, "server_description", str, source->format->charset);
}
- if (str && source->format)
- stats_event_conv (source->mount, "server_description", str, source->format->charset);
/* stream URL */
if (mountinfo && mountinfo->stream_url)
- str = mountinfo->stream_url;
+ stats_event (source->mount, "server_url", mountinfo->stream_url);
else
{
do {
@@ -1147,13 +1150,13 @@
str = httpp_getvar (parser, "x-audiocast-url");
if (str) break;
} while (0);
+ if (str && source->format)
+ stats_event_conv (source->mount, "server_url", str, source->format->charset);
}
- if (str && source->format)
- stats_event_conv (source->mount, "server_url", str, source->format->charset);
/* stream genre */
if (mountinfo && mountinfo->stream_genre)
- str = mountinfo->stream_genre;
+ stats_event (source->mount, "genre", mountinfo->stream_genre);
else
{
do {
@@ -1165,11 +1168,9 @@
if (str) break;
str = "various";
} while (0);
+ if (source->format)
+ stats_event_conv (source->mount, "genre", str, source->format->charset);
}
- if (source->format)
- stats_event_conv (source->mount, "genre", str, source->format->charset);
- else
- stats_event (source->mount, "genre", str);
/* stream bitrate */
if (mountinfo && mountinfo->bitrate)
Modified: icecast/branches/kh/icecast/src/stats.c
===================================================================
--- icecast/branches/kh/icecast/src/stats.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/stats.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -1103,50 +1103,24 @@
}
-/* get a list of mountpoints that are in the stats but are not marked as hidden */
-void stats_get_streamlist (char *buffer, size_t remaining)
-{
- avl_node *node;
- /* now the stats for each source */
- thread_mutex_lock (&_stats_mutex);
- node = avl_get_first(_stats.source_tree);
- while (node)
- {
- int ret;
- stats_source_t *source = (stats_source_t *)node->key;
-
- if (source->hidden == 0)
- {
- if (remaining <= strlen (source->source)+3)
- {
- WARN0 ("streamlist was truncated");
- break;
- }
- ret = snprintf (buffer, remaining, "%s\r\n", source->source);
- if (ret > 0)
- {
- buffer += ret;
- remaining -= ret;
- }
- }
-
- node = avl_get_next(node);
- }
- thread_mutex_unlock (&_stats_mutex);
-}
-
-
-
-/* get a list of refbufs which contain urls for slaves to use for relaying */
-refbuf_t *stats_get_streams (void)
+/* return a list of blocks which contain lines of text. Each line is a mountpoint
+ * reference that a slave will use for relaying. The prepend setting is to indicate
+ * if some something else needs to be added to each line.
+ */
+refbuf_t *stats_get_streams (int prepend)
{
+#define STREAMLIST_BLKSIZE 4096
avl_node *node;
- int remaining = 4096;
+ unsigned int remaining = STREAMLIST_BLKSIZE, prelen;
refbuf_t *start = refbuf_new (remaining), *cur = start;
- const char *pre = "/admin/streams?mount=";
+ const char *pre = "";
char *buffer = cur->data;
+ if (prepend)
+ pre = "/admin/streams?mount=";
+ prelen = strlen (pre);
+
/* now the stats for each source */
thread_mutex_lock (&_stats_mutex);
node = avl_get_first(_stats.source_tree);
@@ -1157,11 +1131,11 @@
if (source->hidden == 0)
{
- if (remaining <= strlen (source->source) + strlen (pre) + 3)
+ if (remaining <= strlen (source->source) + prelen + 3)
{
- cur->len = 4096 - remaining;
- cur->next = refbuf_new (4096);
- remaining = 4096;
+ cur->len = STREAMLIST_BLKSIZE - remaining;
+ cur->next = refbuf_new (STREAMLIST_BLKSIZE);
+ remaining = STREAMLIST_BLKSIZE;
cur = cur->next;
buffer = cur->data;
}
@@ -1175,7 +1149,7 @@
node = avl_get_next(node);
}
thread_mutex_unlock (&_stats_mutex);
- cur->len = 4096 - remaining;
+ cur->len = STREAMLIST_BLKSIZE - remaining;
return start;
}
Modified: icecast/branches/kh/icecast/src/stats.h
===================================================================
--- icecast/branches/kh/icecast/src/stats.h 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/stats.h 2008-05-01 02:28:21 UTC (rev 14821)
@@ -77,7 +77,7 @@
void stats_global(ice_config_t *config);
stats_t *stats_get_stats(void);
void stats_get_streamlist (char *buffer, size_t remaining);
-refbuf_t *stats_get_streams (void);
+refbuf_t *stats_get_streams (int prepend);
void stats_clear_virtual_mounts (void);
void stats_event(const char *source, const char *name, const char *value);
Modified: icecast/branches/kh/icecast/src/yp.c
===================================================================
--- icecast/branches/kh/icecast/src/yp.c 2008-05-01 02:22:06 UTC (rev 14820)
+++ icecast/branches/kh/icecast/src/yp.c 2008-05-01 02:28:21 UTC (rev 14821)
@@ -250,6 +250,8 @@
curl_easy_setopt (server->curl, CURLOPT_WRITEDATA, server->curl);
curl_easy_setopt (server->curl, CURLOPT_TIMEOUT, server->url_timeout);
curl_easy_setopt (server->curl, CURLOPT_NOSIGNAL, 1L);
+ curl_easy_setopt (server->curl, CURLOPT_FOLLOWLOCATION, 1L);
+ curl_easy_setopt (server->curl, CURLOPT_MAXREDIRS, 3L);
curl_easy_setopt (server->curl, CURLOPT_ERRORBUFFER, &(server->curl_error[0]));
server->next = (struct yp_server *)pending_yps;
pending_yps = server;
@@ -278,7 +280,8 @@
/* handler for curl, checks if successful handling occurred
- * return 0 for ok, -1 for this entry failed, -2 for server fail
+ * return 0 for ok, -1 for this entry failed, -2 for server fail.
+ * On failure case, update and process are modified
*/
static int send_to_yp (const char *cmd, ypdata_t *yp, char *post)
{
@@ -293,7 +296,7 @@
if (curlcode)
{
yp->process = do_yp_add;
- yp->next_update += 900;
+ yp->next_update += 1200;
ERROR2 ("connection to %s failed with \"%s\"", server->url, server->curl_error);
return -2;
}
@@ -301,9 +304,28 @@
{
if (yp->error_msg == NULL)
yp->error_msg = strdup ("no response from server");
+ if (yp->process == do_yp_add)
+ {
+ ERROR3 ("YP %s on %s failed: %s", cmd, server->url, yp->error_msg);
+ yp->next_update += 7200;
+ }
+ if (yp->process == do_yp_touch)
+ {
+ /* At this point the touch request failed, either because they rejected our session
+ * or the server isn't accessible. This means we have to wait before doing another
+ * add request. We have a minimum delay but we could allow the directory server to
+ * give us a wait time using the TouchFreq header. This time could be given in such
+ * cases as a firewall block or incorrect listenurl.
+ */
+ if (yp->touch_interval < 1200)
+ yp->next_update += 1200;
+ else
+ yp->next_update += yp->touch_interval;
+ INFO3 ("YP %s on %s failed: %s", cmd, server->url, yp->error_msg);
+ }
yp->process = do_yp_add;
- yp->next_update += 300;
- ERROR3 ("YP %s on %s failed: %s", cmd, server->url, yp->error_msg);
+ free (yp->sid);
+ yp->sid = NULL;
return -1;
}
DEBUG2 ("YP %s at %s succeeded", cmd, server->url);
@@ -327,9 +349,9 @@
free (yp->sid);
yp->sid = NULL;
}
- yp_update = 1;
yp->remove = 1;
yp->process = do_yp_add;
+ yp_update = 1;
return ret;
}
@@ -381,7 +403,7 @@
yp->server_type, yp->subtype, yp->bitrate, yp->audio_info);
if (ret >= (signed)len)
return ret+1;
- ret = send_to_yp ("add", yp, s);
+ ret = send_to_yp ("add", yp, s);
if (ret == 0)
{
yp->process = do_yp_touch;
@@ -449,19 +471,23 @@
if (ret >= (signed)len)
return ret+1; /* space required for above text and nul*/
- return send_to_yp ("touch", yp, s);
+ if (send_to_yp ("touch", yp, s) == 0)
+ {
+ yp->next_update = now + yp->touch_interval;
+ return 0;
+ }
+ return -1;
}
static int process_ypdata (struct yp_server *server, ypdata_t *yp)
{
- unsigned len = 512;
+ unsigned len = 1024;
char *s = NULL, *tmp;
if (now < yp->next_update)
return 0;
- yp->next_update = now + yp->touch_interval;
/* loop just in case the memory area isn't big enough */
while (1)
@@ -872,9 +898,18 @@
thread_rwlock_rlock (&yp_lock);
while (server)
{
- ypdata_t *yp = find_yp_mount (server->mounts, mount);
- if (yp)
+ ypdata_t *list = server->mounts;
+
+ while (1)
{
+ ypdata_t *yp = find_yp_mount (list, mount);
+ if (yp == NULL)
+ break;
+ if (yp->release || yp->remove)
+ {
+ list = yp->next;
+ continue; /* search again these are old entries */
+ }
DEBUG2 ("release %s on YP %s", mount, server->url);
yp->release = 1;
yp->next_update = 0;
More information about the commits
mailing list