[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