[xiph-commits] r16593 - in icecast/branches/kh/icecast: . conf doc src win32

karl at svn.xiph.org karl at svn.xiph.org
Mon Sep 28 18:44:21 PDT 2009


Author: karl
Date: 2009-09-28 18:44:20 -0700 (Mon, 28 Sep 2009)
New Revision: 16593

Modified:
   icecast/branches/kh/icecast/NEWS
   icecast/branches/kh/icecast/conf/icecast.xml.in
   icecast/branches/kh/icecast/config.h.vc6
   icecast/branches/kh/icecast/configure.in
   icecast/branches/kh/icecast/doc/icecast2_listenerauth.html
   icecast/branches/kh/icecast/src/Makefile.am
   icecast/branches/kh/icecast/src/admin.c
   icecast/branches/kh/icecast/src/auth.c
   icecast/branches/kh/icecast/src/auth.h
   icecast/branches/kh/icecast/src/auth_url.c
   icecast/branches/kh/icecast/src/cfgfile.c
   icecast/branches/kh/icecast/src/cfgfile.h
   icecast/branches/kh/icecast/src/client.c
   icecast/branches/kh/icecast/src/client.h
   icecast/branches/kh/icecast/src/connection.c
   icecast/branches/kh/icecast/src/format.c
   icecast/branches/kh/icecast/src/format.h
   icecast/branches/kh/icecast/src/format_mp3.c
   icecast/branches/kh/icecast/src/format_mp3.h
   icecast/branches/kh/icecast/src/format_ogg.c
   icecast/branches/kh/icecast/src/format_ogg.h
   icecast/branches/kh/icecast/src/fserve.c
   icecast/branches/kh/icecast/src/fserve.h
   icecast/branches/kh/icecast/src/global.c
   icecast/branches/kh/icecast/src/global.h
   icecast/branches/kh/icecast/src/refbuf.c
   icecast/branches/kh/icecast/src/refbuf.h
   icecast/branches/kh/icecast/src/sighandler.c
   icecast/branches/kh/icecast/src/slave.c
   icecast/branches/kh/icecast/src/source.c
   icecast/branches/kh/icecast/src/source.h
   icecast/branches/kh/icecast/src/stats.c
   icecast/branches/kh/icecast/src/util.c
   icecast/branches/kh/icecast/src/util.h
   icecast/branches/kh/icecast/win32/Icecast2win.clw
   icecast/branches/kh/icecast/win32/Icecast2win.dsp
   icecast/branches/kh/icecast/win32/Icecast2winDlg.cpp
   icecast/branches/kh/icecast/win32/icecast.dsp
   icecast/branches/kh/icecast/win32/icecast2.iss
   icecast/branches/kh/icecast/win32/icecastService.cpp
Log:
sync up to kh16. A fair bit of this is the format api changes to allow for
use by the file handles, and some compile-time debug code to check for memory
usage.

. We can now fall back to file again without the original stream being present.
. Listener specific intro content can now come via auth listener_add.
. The relay updates for the retry, timeout and disable settings were missed



Modified: icecast/branches/kh/icecast/NEWS
===================================================================
--- icecast/branches/kh/icecast/NEWS	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/NEWS	2009-09-29 01:44:20 UTC (rev 16593)
@@ -16,6 +16,57 @@
 any extra tags are show in the conf/icecast.xml.dist file
 
 
+2.3.2-kh16
+. you can now fallback to file if the initial mountpont is not available as long
+  as there is a limit-rate set at some point within the fallback chain.
+. A header from url listener add "icecast-auth-user: withintro" indicates that
+  the response contains intro data to be sent to the this listener. Anything
+  else indicates the previous behaviour.
+. allow source clients to be limited by duration, set by time limit header in
+  url stream auth
+. internal changes to average bitrate calculations. blocks are now removed based
+  on the timestamp not the block count.
+. fix possible race with url auth'd listener getting a 404 response
+. try throttle file sending based on duration/bytes sent on file handle and split the
+  file sending function into two (throttled/unthrottled). reduces memory.
+. merge in compile-time allocation counters
+. Added some stats for fallback files, and metadata_updated for sources
+. minor cleanups for internal API. log message cleanups.
+. kh15b. fix possible crash on url listener failing.
+. kh15a
+  - fix memory corruption when clients are referring to the same file.
+  - log buffering on win32 enabled
+
+2.3.2-kh15
+. lock mismatch identified, could cause a stall in the worker.
+. relay connection timeout was not being set in all cases
+. Don't fallback listeners on relay fail if server shutting down
+. minor code cleanups.
+
+2.3.2-kh14
+. Allow stats/listclients/killclient work with file references
+. Add timeout parameter to relay. number of seconds for connect to complete.
+. fixes for restarting of relays, especially where changes are detected and
+  where fallback to files were set.
+. repeat fallback file
+. tuneup client scheduling for file sending
+. added a few validation checks, useragent chars, xml config port ranges
+. log message cleanups.
+
+2.3.2-kh13
+. on source exit, listeners do not need to be moved to the file serving engine,
+  just release any shared data and delete client if not on worker. saves process
+  work at source exit
+. fix possible crash bug with long lock held detection.
+. allow listener_add response to include intro content
+. merge connection_t into client_t, and shrunk connection_t, reduces memory used
+. improve some of the internal client scheduling.
+. the reading of the mime types file was done too early
+. admin/fallback now updates the mount details if available.
+. more source lock cleanups. nothing major
+. change the order of the header routines, the format specific routine now calls
+  the general routine.
+
 2.3.2-kh12
 . xml based relays could cause a crash on server exit or xml reload
 . avoid memory/fd leak on active relay restart.

Modified: icecast/branches/kh/icecast/conf/icecast.xml.in
===================================================================
--- icecast/branches/kh/icecast/conf/icecast.xml.in	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/conf/icecast.xml.in	2009-09-29 01:44:20 UTC (rev 16593)
@@ -100,13 +100,13 @@
     <!-- Allow multiple master servers to be specified, tries each one in turn.
     <relay>
         <local-mount>/stream.mp3</local-mount>
+        <server>a.b.c.d</server>
+        <timeout>6</timeout>
         <master>
-            <server>a.b.c.d</server>
             <port>8000</port>
             <mount>/a</mount>
         </master>
         <master>
-            <server>a.b.c.d</server>
             <port>80</port>
             <mount>/</mount>
         </master>

Modified: icecast/branches/kh/icecast/config.h.vc6
===================================================================
--- icecast/branches/kh/icecast/config.h.vc6	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/config.h.vc6	2009-09-29 01:44:20 UTC (rev 16593)
@@ -95,7 +95,7 @@
 #define PACKAGE_NAME "Icecast"
 
 /* Version number of package */
-#define VERSION "2.3.2-kh12"
+#define VERSION "2.3.2-kh16"
 
 /* Define to the version of this package. */
 #define PACKAGE_VERSION VERSION
@@ -159,6 +159,7 @@
 #define HAVE_SYS_TIMEB_H 1
 
 #define sock_t SOCKET
+#define sockaddr_storage sockaddr_in
 
 /* time format for strftime */
 #define ICECAST_TIME_FMT "%a, %d %b %Y %H:%M:%S"

Modified: icecast/branches/kh/icecast/configure.in
===================================================================
--- icecast/branches/kh/icecast/configure.in	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/configure.in	2009-09-29 01:44:20 UTC (rev 16593)
@@ -1,4 +1,4 @@
-AC_INIT([Icecast], [2.3.2-kh12], [karl at xiph.org])
+AC_INIT([Icecast], [2.3.2-kh16], [karl at xiph.org])
 
 AC_PREREQ(2.59)
 AC_CONFIG_SRCDIR(src/main.c)

Modified: icecast/branches/kh/icecast/doc/icecast2_listenerauth.html
===================================================================
--- icecast/branches/kh/icecast/doc/icecast2_listenerauth.html	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/doc/icecast2_listenerauth.html	2009-09-29 01:44:20 UTC (rev 16593)
@@ -51,8 +51,8 @@
 <h3>Configuring Users and Passwords</h3>
 <p>Once the appropriate entries are made to the config file, connect your source client (using the mountpoint you named in the config file).  To configure users and passwords for this stream you must use the web-based admin interface.  Navigate to http://server:ip/admin/stats.xsl to begin.  If you have configured everything properly, you should see a screen like the following :</p>
 <img src="listener_auth1.jpg" alt="Screenshot of http://server:ip/admin/stats.xsl" />
-<p>You will see a red key in front of all mountpoint configured for listener authentication.  Also note that this page will only show CONNECTED mountpoints.</p>
-<p>To manage users and passwords for this mountpoint, click on the red key or follow the "Manage Authentication" link.  The following screen will be shown :</p>
+<p>You will see a lock in front of all mountpoint configured for listener authentication.  Also note that this page will only show CONNECTED mountpoints.</p>
+<p>To manage users and passwords for this mountpoint, click on the lock or follow the "Manage Authentication" link.  The following screen will be shown :</p>
 <img src="listener_auth2.jpg" alt="Screenshot of Manage Authentication" />
 <p>This screen will show all the users configured for this mountpoint.  Adding users is as simple as entering a username and password in the fields and clicking "Add New User".  Note that usernames MUST be unique and there are NO restrictions on passwords.  You can delete users by clicking the appropriate delete link next to each user.</p>
 <br />

Modified: icecast/branches/kh/icecast/src/Makefile.am
===================================================================
--- icecast/branches/kh/icecast/src/Makefile.am	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/Makefile.am	2009-09-29 01:44:20 UTC (rev 16593)
@@ -10,7 +10,7 @@
     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 \
+    fnmatch_loop.c fnmatch.h \
     format.h format_ogg.h format_mp3.h \
     format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \
     format_kate.h format_skeleton.h

Modified: icecast/branches/kh/icecast/src/admin.c
===================================================================
--- icecast/branches/kh/icecast/src/admin.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/admin.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -106,7 +106,7 @@
 
 static struct admin_command admin_mount[] =
 {
-    { "fallbacks",          RAW,    { command_fallback } },
+    { "fallback",           RAW,    { command_fallback } },
     { "metadata",           RAW,    { command_metadata } },
     { "listclients",        RAW,    { command_show_listeners } },
     { "updatemetadata",     RAW,    { command_updatemetadata } },
@@ -283,8 +283,23 @@
 
     if (source == NULL)
     {
+        avl_tree_unlock(global.source_tree);
+        if (strncmp (cmd->request, "stats", 5) == 0)
+        {
+            fserve_list_clients (client, mount, cmd->response, 0);
+            return;
+        }
+        if (strncmp (cmd->request, "listclients", 11) == 0)
+        {
+            fserve_list_clients (client, mount, cmd->response, 1);
+            return;
+        }
+        if (strncmp (cmd->request, "killclient", 10) == 0)
+        {
+            fserve_kill_client (client, mount, cmd->response);
+            return;
+        }
         WARN1("Admin command on non-existent source %s", mount);
-        avl_tree_unlock(global.source_tree);
         client_send_400 (client, "Source does not exist");
     }
     else
@@ -623,7 +638,7 @@
     xmlNewChild (node, NULL, XMLSTR("ip"), XMLSTR(listener->connection.ip));
 
     useragent = httpp_getvar (listener->parser, "user-agent");
-    if (useragent)
+    if (useragent && xmlCheckUTF8((unsigned char *)useragent))
     {
         xmlChar *str = xmlEncodeEntitiesReentrant (srcnode->doc, XMLSTR(useragent));
         xmlNewChild (node, NULL, XMLSTR("useragent"), str); 
@@ -1118,6 +1133,7 @@
 
 static void command_stats_mount (client_t *client, source_t *source, int response)
 {
+    thread_mutex_unlock (&source->lock);
     command_stats (client, NULL);
 }
 /* catch all function for admin requests.  If file has xsl extension then

Modified: icecast/branches/kh/icecast/src/auth.c
===================================================================
--- icecast/branches/kh/icecast/src/auth.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/auth.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -366,7 +366,7 @@
 }
 
 
-void move_listener (client_t *client, struct _fbinfo *finfo)
+int move_listener (client_t *client, struct _fbinfo *finfo)
 {
     source_t *source;
 
@@ -382,7 +382,7 @@
             avl_tree_unlock (global.source_tree);
             source_setup_listener (source, client);
             thread_mutex_unlock (&source->lock);
-            return;
+            return 0;
         }
         if (source->fallback.mount)
         {
@@ -392,7 +392,9 @@
         }
     }
     avl_tree_unlock (global.source_tree);
-    fserve_setup_client_fb (client, finfo);
+    if (client->flags & CLIENT_IS_SLAVE)
+        return -1;
+    return fserve_setup_client_fb (client, finfo);
 }
 
 
@@ -448,6 +450,8 @@
         }
         ret = fserve_client_create (client, mount);
     }
+    if (ret == 0)
+        global_reduce_bitrate_sampling (global.out_bitrate);
     return ret;
 }
 
@@ -460,12 +464,10 @@
     ice_config_t *config;
     mount_proxy *mountinfo;
     const char *mount = auth_user->mount;
-    worker_t *worker;
 
     if (client == NULL)
         return -1;
 
-    worker = client->worker;
     if ((client->flags & CLIENT_AUTHENTICATED) == 0)
     {
         /* auth failed so do we place the listener elsewhere */

Modified: icecast/branches/kh/icecast/src/auth.h
===================================================================
--- icecast/branches/kh/icecast/src/auth.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/auth.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -107,7 +107,7 @@
 
 void auth_add_listener (const char *mount, client_t *client);
 int  auth_release_listener (client_t *client, const char *mount, struct _mount_proxy *mountinfo);
-void move_listener (client_t *client, struct _fbinfo *finfo);
+int  move_listener (client_t *client, struct _fbinfo *finfo);
 int  auth_check_source (client_t *client, const char *mount);
 
 void auth_initialise (void);

Modified: icecast/branches/kh/icecast/src/auth_url.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_url.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/auth_url.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -123,7 +123,7 @@
 {
     auth_url *url;
 
-    INFO0 ("Doing auth URL cleanup");
+    INFO1 ("Doing auth URL cleanup for %s", self->mount);
     url = self->state;
     self->state = NULL;
     free (url->username);
@@ -157,13 +157,18 @@
     client_t *client = auth_user->client;
     auth_thread_data *atd = auth_user->thread_data;
 
+    if (bytes <= 1) // we should have the EOL at least
+        return bytes;
     if (client)
     {
         auth_t *auth = auth_user->auth;
         auth_url *url = auth->state;
         int retcode = 0;
+        char *p = ptr;
 
-        if (sscanf (ptr, "HTTP/%*u.%*u %3d %*c", &retcode) == 1)
+        /* replace the EOL with a nul char, libcurl may not provide a nul */
+        p[bytes-2] = '\0';
+        if (sscanf (ptr, "HTTP%*c%*u.%*u %3d %*c", &retcode) == 1)
         {
             if (retcode == 403)
             {
@@ -174,7 +179,21 @@
             }
         }
         if (strncasecmp (ptr, url->auth_header, url->auth_header_len) == 0)
+        {
             client->flags |= CLIENT_AUTHENTICATED;
+            p = strchr (ptr, ':');
+            if (p)
+            {
+                ++p;
+                if (strstr (p, "withintro"))
+                    client->flags |= CLIENT_HAS_INTRO_CONTENT;
+                if (strstr (p, "0"))
+                {
+                    WARN0 ("auth header returned with 0 value");
+                    client->flags &= ~CLIENT_AUTHENTICATED;
+                }
+            }
+        }
         if (strncasecmp (ptr, url->timelimit_header, url->timelimit_header_len) == 0)
         {
             unsigned int limit = 0;
@@ -219,12 +238,12 @@
     unsigned bytes = size * nmemb;
     client_t *client = auth_user->client;
 
-    if (client && client->respcode == 0)
+    if (client && client->respcode == 0 &&
+         client->flags & CLIENT_HAS_INTRO_CONTENT)
     {
         refbuf_t *n, *r = client->refbuf;
         struct build_intro_contents *x = (void*)r->data;
 
-        client->flags |= CLIENT_HAS_INTRO_CONTENT;
         n = refbuf_new (bytes);
         memcpy (n->data, ptr, bytes);
         *x->tailp = n;
@@ -426,14 +445,26 @@
     {
         if (client->flags & CLIENT_HAS_INTRO_CONTENT)
             client->refbuf->next = x->head;
+        if (x->head == NULL)
+            client->flags &= ~CLIENT_HAS_INTRO_CONTENT;
+
         return AUTH_OK;
     }
+    /* better cleanup memory */
+    while (x->head)
+    {
+        refbuf_t *n = x->head;
+        x->head = n->next;
+        n->next = NULL;
+        refbuf_release (n);
+    }
+    auth_user->client = NULL;
     if (atoi (atd->errormsg) == 403)
-    {
         client_send_403 (client, atd->errormsg+4);
-        auth_user->client = NULL;
-    }
-    INFO2 ("client auth (%s) failed with \"%s\"", url->addurl, atd->errormsg);
+    else
+        client_send_401 (client, auth_user->auth->realm);
+    if (atd->errormsg[0])
+        INFO2 ("client auth (%s) failed with \"%s\"", url->addurl, atd->errormsg);
     return AUTH_FAILED;
 }
 
@@ -612,7 +643,7 @@
     curl_easy_cleanup (atd->curl);
     free (atd->server_id);
     free (atd);
-    INFO1 ("...handler destroyed for %s", auth->mount);
+    DEBUG1 ("...handler destroyed for %s", auth->mount);
 }
 
 
@@ -628,7 +659,7 @@
     authenticator->release_thread_data = release_thread_data;
 
     url_info = calloc(1, sizeof(auth_url));
-    url_info->auth_header = strdup ("icecast-auth-user: 1\r\n");
+    url_info->auth_header = strdup ("icecast-auth-user:");
     url_info->timelimit_header = strdup ("icecast-auth-timelimit:");
 
     while(options) {

Modified: icecast/branches/kh/icecast/src/cfgfile.c
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/cfgfile.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -836,6 +836,7 @@
         { "port",           config_get_int,     &master->port },
         { "mount",          config_get_str,     &master->mount },
         { "bind",           config_get_str,     &master->bind },
+        { "timeout",        config_get_int,     &master->timeout },
         { NULL, NULL, NULL },
     };
 
@@ -845,10 +846,16 @@
     if (relay->masters->bind)
         master->bind = (char *)xmlCharStrdup (relay->masters->bind);
     master->port = relay->masters->port;
+    master->timeout = relay->masters->timeout;
 
     if (parse_xml_tags (node, icecast_tags))
         return -1;
 
+    if (master->port < 1 || master->port > 65535)
+        master->port = 8000;
+    if (master->timeout < 1 || master->timeout > 60)
+        master->timeout = 4;
+
     /* place new details at the end of the list */
     last = relay->masters;
     while (last->next)
@@ -873,6 +880,7 @@
         { "bind",           config_get_str,     &master->bind },
         { "port",           config_get_int,     &master->port },
         { "mount",          config_get_str,     &master->mount },
+        { "timeout",        config_get_int,     &master->timeout },
         { "local-mount",    config_get_str,     &relay->localmount },
         { "on-demand",      config_get_bool,    &relay->on_demand },
         { "retry-delay",    config_get_int,     &relay->interval },
@@ -893,6 +901,7 @@
     master->port = config->port;
     master->ip = (char *)xmlCharStrdup ("127.0.0.1");
     master->mount = (char*)xmlCharStrdup ("/");
+    master->timeout = 4;
 
     if (parse_xml_tags (node, icecast_tags))
         return -1;

Modified: icecast/branches/kh/icecast/src/cfgfile.h
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/cfgfile.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -138,6 +138,7 @@
     char *bind;
     char *mount;
     int port;
+    int timeout;
 } relay_server_master;
 
 typedef struct _relay_server

Modified: icecast/branches/kh/icecast/src/client.c
===================================================================
--- icecast/branches/kh/icecast/src/client.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/client.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -464,13 +464,14 @@
 
 static void worker_stop (void)
 {
-    worker_t *handler = workers;
+    worker_t *handler;
     client_t *clients = NULL, **last;
     int count;
 
-    if (handler == NULL)
+    if (workers == NULL)
         return;
     thread_rwlock_wlock (&workers_lock);
+    handler = workers;
     workers = handler->next;
     worker_count--;
     thread_rwlock_unlock (&workers_lock);

Modified: icecast/branches/kh/icecast/src/client.h
===================================================================
--- icecast/branches/kh/icecast/src/client.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/client.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -102,8 +102,8 @@
     /* the worker the client is attached to */
     worker_t *worker;
 
-    /* for cases where we want to limit data rates */
-    struct rate_calc *out_bitrate;
+    time_t timer_start;
+    uint64_t counter;
 
     /* function to call to release format specific resources */
     void (*free_client_data)(struct _client_tag *client);

Modified: icecast/branches/kh/icecast/src/connection.c
===================================================================
--- icecast/branches/kh/icecast/src/connection.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/connection.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -708,7 +708,7 @@
                 client->shared_data = NULL;
                 client->check_buffer = format_generic_write_to_client;
                 fserve_setup_client_fb (client, &fb);
-                return 1;
+                return 0;
             }
             /* find a blank line */
             do
@@ -782,7 +782,7 @@
                         WARN0("unhandled request type from client");
                         client_send_400 (client, "unknown request");
                 }
-                return 1;
+                return 0;
             }
             /* invalid http request */
             return -1;
@@ -897,7 +897,10 @@
             format_type = FORMAT_TYPE_GENERIC;
         }
 
-        if (format_get_plugin (format_type, source) < 0)
+        source->format->type = format_type;
+        source->format->mount = source->mount;
+        source->format->parser = source->parser;
+        if (format_get_plugin (source->format) < 0)
         {
             global_unlock();
             config_release_config();

Modified: icecast/branches/kh/icecast/src/format.c
===================================================================
--- icecast/branches/kh/icecast/src/format.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/format.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -61,28 +61,29 @@
         return FORMAT_TYPE_GENERIC;
 }
 
-void format_free_plugin (format_plugin_t *format)
+void format_plugin_clear (format_plugin_t *format)
 {
     if (format == NULL)
         return;
     rate_free (format->in_bitrate);
     rate_free (format->out_bitrate);
     free (format->charset);
+    format->charset = NULL;
     if (format->free_plugin)
         format->free_plugin (format);
 }
 
 
-int format_get_plugin (format_type_t type, source_t *source)
+int format_get_plugin (format_plugin_t *plugin)
 {
     int ret = -1;
 
-    switch (type) {
+    switch (plugin->type) {
     case FORMAT_TYPE_OGG:
-        ret = format_ogg_get_plugin (source);
+        ret = format_ogg_get_plugin (plugin);
         break;
     case FORMAT_TYPE_GENERIC:
-        ret = format_mp3_get_plugin (source);
+        ret = format_mp3_get_plugin (plugin);
         break;
     default:
         break;
@@ -151,7 +152,7 @@
 }
 
 
-int format_general_headers (source_t *source, client_t *client)
+int format_general_headers (format_plugin_t *plugin, client_t *client)
 {
     unsigned remaining = 4096 - client->refbuf->len;
     char *ptr = client->refbuf->data + client->refbuf->len;
@@ -163,69 +164,72 @@
     if (client->respcode == 0)
     {
         bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"
-                "Content-Type: %s\r\n", source->format->contenttype);
+                "Content-Type: %s\r\n", plugin->contenttype);
         remaining -= bytes;
         ptr += bytes;
         client->respcode = 200;
     }
 
-    /* iterate through source http headers and send to client */
-    avl_tree_rlock (source->parser->vars);
-    node = avl_get_first (source->parser->vars);
-    while (node)
+    if (plugin->parser)
     {
-        int next = 1;
-        http_var_t *var = (http_var_t *)node->key;
-        bytes = 0;
-        if (!strcasecmp (var->name, "ice-audio-info"))
+        /* iterate through source http headers and send to client */
+        avl_tree_rlock (plugin->parser->vars);
+        node = avl_get_first (plugin->parser->vars);
+        while (node)
         {
-            /* convert ice-audio-info to icy-br */
-            char *brfield = NULL;
-            unsigned int bitrate;
+            int next = 1;
+            http_var_t *var = (http_var_t *)node->key;
+            bytes = 0;
+            if (!strcasecmp (var->name, "ice-audio-info"))
+            {
+                /* convert ice-audio-info to icy-br */
+                char *brfield = NULL;
+                unsigned int bitrate;
 
-            if (bitrate_filtered == 0)
-                brfield = strstr (var->value, "bitrate=");
-            if (brfield && sscanf (brfield, "bitrate=%u", &bitrate))
-            {
-                bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate);
-                next = 0;
-                bitrate_filtered = 1;
+                if (bitrate_filtered == 0)
+                    brfield = strstr (var->value, "bitrate=");
+                if (brfield && sscanf (brfield, "bitrate=%u", &bitrate))
+                {
+                    bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate);
+                    next = 0;
+                    bitrate_filtered = 1;
+                }
+                else
+                    /* show ice-audio_info header as well because of relays */
+                    bytes = snprintf (ptr, remaining, "%s: %s\r\n", var->name, var->value);
             }
             else
-                /* show ice-audio_info header as well because of relays */
-                bytes = snprintf (ptr, remaining, "%s: %s\r\n", var->name, var->value);
-        }
-        else
-        {
-            if (strcasecmp (var->name, "ice-password") &&
-                    strcasecmp (var->name, "icy-metaint"))
             {
-                if (!strncasecmp ("ice-", var->name, 4))
+                if (strcasecmp (var->name, "ice-password") &&
+                        strcasecmp (var->name, "icy-metaint"))
                 {
-                    if (!strcasecmp ("ice-public", var->name))
-                        bytes = snprintf (ptr, remaining, "icy-pub:%s\r\n", var->value);
-                    else
-                        if (!strcasecmp ("ice-bitrate", var->name))
-                            bytes = snprintf (ptr, remaining, "icy-br:%s\r\n", var->value);
+                    if (!strncasecmp ("ice-", var->name, 4))
+                    {
+                        if (!strcasecmp ("ice-public", var->name))
+                            bytes = snprintf (ptr, remaining, "icy-pub:%s\r\n", var->value);
                         else
+                            if (!strcasecmp ("ice-bitrate", var->name))
+                                bytes = snprintf (ptr, remaining, "icy-br:%s\r\n", var->value);
+                            else
+                                bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
+                                        var->name + 3, var->value);
+                    }
+                    else 
+                        if (!strncasecmp ("icy-", var->name, 4))
+                        {
                             bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                     var->name + 3, var->value);
+                        }
                 }
-                else 
-                    if (!strncasecmp ("icy-", var->name, 4))
-                    {
-                        bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
-                                var->name + 3, var->value);
-                    }
             }
+
+            remaining -= bytes;
+            ptr += bytes;
+            if (next)
+                node = avl_get_next (node);
         }
-
-        remaining -= bytes;
-        ptr += bytes;
-        if (next)
-            node = avl_get_next (node);
+        avl_tree_unlock (plugin->parser->vars);
     }
-    avl_tree_unlock (source->parser->vars);
 
     config = config_get_config();
     bytes = snprintf (ptr, remaining, "Server: %s\r\n", config->server_id);
@@ -243,6 +247,7 @@
     ptr += bytes;
 
     client->refbuf->len = 4096 - remaining;
+    client->refbuf->flags |= WRITE_BLOCK_GENERIC;
     return 0;
 }
 

Modified: icecast/branches/kh/icecast/src/format.h
===================================================================
--- icecast/branches/kh/icecast/src/format.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/format.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -31,24 +31,27 @@
     FORMAT_TYPE_GENERIC
 } format_type_t;
 
-typedef struct _format_plugin_tag
+typedef struct _format_plugin_tag format_plugin_t;
+
+struct _format_plugin_tag
 {
     format_type_t type;
 
     /* we need to know the mount to report statistics */
     char *mount;
 
-    const char *contenttype;
+    char *contenttype;
     char *charset;
     uint64_t read_bytes;
     uint64_t sent_bytes;
     struct rate_calc *in_bitrate;
     struct rate_calc *out_bitrate;
+    http_parser_t *parser;
 
     refbuf_t *(*get_buffer)(struct source_tag *);
     int (*write_buf_to_client)(client_t *client);
     void (*write_buf_to_file)(struct source_tag *source, refbuf_t *refbuf);
-    int (*create_client_data)(struct source_tag *source, client_t *client);
+    int (*create_client_data)(format_plugin_t *plugin, client_t *client);
     void (*set_tag)(struct _format_plugin_tag *plugin, const char *tag, const char *value, const char *charset);
     void (*free_plugin)(struct _format_plugin_tag *self);
     void (*apply_settings)(client_t *client, struct _format_plugin_tag *format, struct _mount_proxy *mount);
@@ -56,20 +59,19 @@
 
     /* for internal state management */
     void *_state;
-} format_plugin_t;
+};
 
 format_type_t format_get_type(const char *contenttype);
-int format_get_plugin(format_type_t type, struct source_tag *source);
-
+int format_get_plugin (format_plugin_t *plugin);
 int format_generic_write_to_client (client_t *client);
 
 int format_file_read (client_t *client, FILE *fp);
-int format_general_headers (struct source_tag *source, client_t *client);
+int format_general_headers (format_plugin_t *plugin, client_t *client);
 
 void format_send_general_headers(format_plugin_t *format, 
         struct source_tag *source, client_t *client);
 
-void format_free_plugin (format_plugin_t *format);
+void format_plugin_clear (format_plugin_t *format);
 
 #endif  /* __FORMAT_H__ */
 

Modified: icecast/branches/kh/icecast/src/format_mp3.c
===================================================================
--- icecast/branches/kh/icecast/src/format_mp3.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/format_mp3.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -51,7 +51,7 @@
 static refbuf_t *mp3_get_filter_meta (source_t *source);
 static refbuf_t *mp3_get_no_meta (source_t *source);
 
-static int  format_mp3_create_client_data (source_t *source, client_t *client);
+static int  format_mp3_create_client_data (format_plugin_t *plugin, client_t *client);
 static void free_mp3_client_data (client_t *client);
 static int format_mp3_write_buf_to_client(client_t *client);
 static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf);
@@ -73,17 +73,13 @@
 static refbuf_t blank_meta = { 17, 1, "\001StreamTitle='';", NULL, NULL, 0 };
 
 
-int format_mp3_get_plugin (source_t *source)
+int format_mp3_get_plugin (format_plugin_t *plugin)
 {
     const char *metadata;
-    format_plugin_t *plugin;
     mp3_state *state = calloc(1, sizeof(mp3_state));
     refbuf_t *meta;
+    const char *s;
 
-    plugin = (format_plugin_t *)calloc(1, sizeof(format_plugin_t));
-
-    plugin->mount = source->mount;
-    plugin->type = FORMAT_TYPE_GENERIC;
     plugin->get_buffer = mp3_get_no_meta;
     plugin->write_buf_to_client = format_mp3_write_buf_to_client;
     plugin->write_buf_to_file = write_mp3_to_file;
@@ -92,11 +88,12 @@
     plugin->set_tag = mp3_set_tag;
     plugin->apply_settings = format_mp3_apply_settings;
 
-    plugin->contenttype = httpp_getvar (source->parser, "content-type");
-    if (plugin->contenttype == NULL) {
+    s = httpp_getvar (plugin->parser, "content-type");
+    if (s)
+        plugin->contenttype = strdup (s);
+    else
         /* We default to MP3 audio for old clients without content types */
-        plugin->contenttype = "audio/mpeg";
-    }
+        plugin->contenttype = strdup ("audio/mpeg");
 
     plugin->_state = state;
 
@@ -107,7 +104,7 @@
     state->metadata = meta;
     state->interval = -1;
 
-    metadata = httpp_getvar (source->parser, "icy-metaint");
+    metadata = httpp_getvar (plugin->parser, "icy-metaint");
     if (metadata)
     {
         state->inline_metadata_interval = atoi (metadata);
@@ -118,7 +115,6 @@
             state->interval = state->inline_metadata_interval;
         }
     }
-    source->format = plugin;
     thread_mutex_create (&state->url_lock);
 
     return 0;
@@ -159,6 +155,7 @@
         free (source_mp3->url_title);
         source_mp3->url_title = value;
         stats_event (plugin->mount, "title", value);
+        stats_event_time (plugin->mount, "metadata_updated");
     }
     else if (strcmp (tag, "artist") == 0)
     {
@@ -494,8 +491,8 @@
     free (format_mp3->url);
     refbuf_release (format_mp3->metadata);
     refbuf_release (format_mp3->read_data);
-    free(format_mp3);
-    free(plugin);
+    free (plugin->contenttype);
+    free (format_mp3);
 }
 
 
@@ -657,6 +654,7 @@
                         source_mp3->build_metadata, source_mp3->build_metadata_len);
                 logging_playlist (source->mount, title, source->listeners);
                 stats_event_conv (source->mount, "title", title, source->format->charset);
+                stats_event_time (source->mount, "metadata_updated");
                 yp_touch (source->mount);
                 free (title);
                 refbuf_release (source_mp3->metadata);
@@ -690,10 +688,10 @@
 }
 
 
-static int format_mp3_create_client_data(source_t *source, client_t *client)
+static int format_mp3_create_client_data (format_plugin_t *plugin, client_t *client)
 {
     mp3_client_data *client_mp3 = calloc(1,sizeof(mp3_client_data));
-    mp3_state *source_mp3 = source->format->_state;
+    mp3_state *source_mp3 = plugin->_state;
     const char *metadata;
     size_t  remaining = 4096;
     char *ptr = client->refbuf->data;
@@ -722,7 +720,7 @@
     client->free_client_data = free_mp3_client_data;
     client->refbuf->len = 4096 - remaining;
 
-    if (format_general_headers (source, client) < 0)
+    if (format_general_headers (plugin, client) < 0)
         return -1;
 
     remaining = 4096 - client->refbuf->len + 2;

Modified: icecast/branches/kh/icecast/src/format_mp3.h
===================================================================
--- icecast/branches/kh/icecast/src/format_mp3.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/format_mp3.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -40,6 +40,6 @@
     char build_metadata[4081];
 } mp3_state;
 
-int format_mp3_get_plugin(struct source_tag *src);
+int format_mp3_get_plugin (format_plugin_t *plugin);
 
 #endif  /* __FORMAT_MP3_H__ */

Modified: icecast/branches/kh/icecast/src/format_ogg.c
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/format_ogg.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -51,7 +51,7 @@
 struct _ogg_state_tag;
 
 static void format_ogg_free_plugin (format_plugin_t *plugin);
-static int  create_ogg_client_data(source_t *source, client_t *client);
+static int  create_ogg_client_data(format_plugin_t *plugin, client_t *client);
 static void free_ogg_client_data (client_t *client);
 
 static int get_image (client_t *client, struct _format_plugin_tag *format);
@@ -156,14 +156,10 @@
 }
 
 
-int format_ogg_get_plugin (source_t *source)
+int format_ogg_get_plugin (format_plugin_t *plugin)
 {
-    format_plugin_t *plugin;
     ogg_state_t *state = calloc (1, sizeof (ogg_state_t));
 
-    plugin = (format_plugin_t *)calloc(1, sizeof(format_plugin_t));
-
-    plugin->type = FORMAT_TYPE_OGG;
     plugin->get_buffer = ogg_get_buffer;
     plugin->write_buf_to_client = write_buf_to_client;
     plugin->write_buf_to_file = write_ogg_to_file;
@@ -172,15 +168,20 @@
     plugin->get_image = get_image;
     plugin->set_tag = NULL;
     plugin->apply_settings = apply_ogg_settings;
-    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");;
+    if (plugin->parser)
+    {
+        const char *s = httpp_getvar (plugin->parser, "content-type");;
+        if (s==NULL || strcmp (s, "application/x-ogg") == 0)
+            httpp_setvar (plugin->parser, "content-type", "application/ogg");
+        plugin->contenttype = strdup (httpp_getvar (plugin->parser, "content-type"));
+    }
+    else
+        plugin->contenttype = strdup ("application/ogg");
 
     ogg_sync_init (&state->oy);
 
     plugin->_state = state;
-    source->format = plugin;
-    state->mount = source->mount;
+    state->mount = plugin->mount;
     state->bos_end = &state->header_pages;
 
     return 0;
@@ -198,8 +199,7 @@
 
     ogg_sync_clear (&state->oy);
     free (state);
-
-    free (plugin);
+    free (plugin->contenttype);
 }
 
 
@@ -336,6 +336,7 @@
     }
     stats_event (source->mount, "artist", artist);
     stats_event (source->mount, "title", title);
+    stats_event_time (source->mount, "metadata_updated");
 
     codec = ogg_info->codecs;
     while (codec)
@@ -474,7 +475,7 @@
 }
 
 
-static int create_ogg_client_data (source_t *source, client_t *client) 
+static int create_ogg_client_data (format_plugin_t *plugin, client_t *client) 
 {
     struct ogg_client *client_data = calloc (1, sizeof (struct ogg_client));
     int ret = -1;
@@ -484,7 +485,7 @@
         client_data->headers_sent = 1;
         client->format_data = client_data;
         client->free_client_data = free_ogg_client_data;
-        ret = format_general_headers (source, client);
+        ret = format_general_headers (plugin, client);
     }
     return ret;
 }

Modified: icecast/branches/kh/icecast/src/format_ogg.h
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/format_ogg.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -72,6 +72,6 @@
 refbuf_t *make_refbuf_with_page (ogg_codec_t *codec, ogg_page *page);
 void format_ogg_attach_header (ogg_codec_t *codec, ogg_page *page);
 void format_ogg_free_headers (ogg_state_t *ogg_info);
-int format_ogg_get_plugin (source_t *source);
+int  format_ogg_get_plugin (format_plugin_t *plugin);
 
 #endif  /* __FORMAT_OGG_H__ */

Modified: icecast/branches/kh/icecast/src/fserve.c
===================================================================
--- icecast/branches/kh/icecast/src/fserve.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/fserve.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -76,6 +76,9 @@
     mutex_t lock;
     int refcount;
     FILE *fp;
+    time_t stats_update;
+    format_plugin_t *format;
+    client_t *clients;
 } fh_node;
 
 int fserve_running;
@@ -179,8 +182,6 @@
     if (r) return r;
     r = (int)x->finfo.flags - y->finfo.flags;
     if (r) return r;
-    if (x->finfo.flags & FS_JINGLE)
-        return strcmp (x->finfo.fallback, y->finfo.fallback);
     return 0;
 }
 
@@ -196,6 +197,12 @@
     }
     if (fh->fp)
         fclose (fh->fp);
+    stats_event (fh->finfo.mount, NULL, NULL);
+    if (fh->format)
+    {
+        format_plugin_clear (fh->format);
+        free (fh->format);
+    }
     free (fh->finfo.mount);
     free (fh->finfo.fallback);
     free (fh);
@@ -203,8 +210,26 @@
     return 1;
 }
 
+
+static void remove_from_fh (fh_node *fh, client_t *client)
+{
+    client_t **p = &fh->clients;
+    while (*p)
+    {
+        if (*p == client)
+        {
+            *p = client->next;
+            return;
+        }
+        p = &(*p)->next;
+    }
+    if (fh->finfo.mount)
+        DEBUG0 ("unable to find client");
+}
+
+
 /* find/create handle and return it with the structure in a locked state */
-static fh_node *open_fh (fbinfo *finfo)
+static fh_node *open_fh (fbinfo *finfo, client_t *client)
 {
     fh_node *fh, *result;
 
@@ -218,6 +243,21 @@
         free (fh);
         thread_mutex_lock (&result->lock);
         result->refcount++;
+        if (client)
+        {
+            if (finfo->mount && (finfo->flags & FS_FALLBACK))
+                stats_event_args (result->finfo.mount, "listeners", "%ld", result->refcount);
+            client->next = result->clients;
+            result->clients = client;
+            if (result->format)
+            {
+                if (result->format->create_client_data && client->format_data == NULL)
+                {
+                    result->format->create_client_data (result->format, client);
+                    client->check_buffer = result->format->write_buf_to_client;
+                }
+            }
+        }
         DEBUG2 ("refcount now %d for %s", result->refcount, result->finfo.mount);
         avl_tree_unlock (fh_cache);
         return result;
@@ -227,15 +267,60 @@
     if (fh->finfo.mount[0])
     {
         char *fullpath= util_get_path_from_normalised_uri (fh->finfo.mount, fh->finfo.flags&FS_USE_ADMIN);
-        DEBUG1 ("lookup of \"%s\"", finfo->mount);
+        if (client)
+        {
+            if (finfo->flags & FS_FALLBACK)
+                DEBUG1 ("lookup of fallback file \"%s\"", finfo->mount);
+            else
+                DEBUG1 ("lookup of \"%s\"", finfo->mount);
+        }
         fh->fp = fopen (fullpath, "rb");
         if (fh->fp == NULL)
-            WARN1 ("Failed to open \"%s\"", fullpath);
+        {
+            if (client)
+                WARN1 ("Failed to open \"%s\"", fullpath);
+            if (finfo->flags & FS_FALLBACK)
+            {
+                avl_tree_unlock (fh_cache);
+                free (fullpath);
+                free (fh);
+                return NULL;
+            }
+        }
+        if (client && finfo->flags & FS_FALLBACK)
+        {
+            char *contenttype = fserve_content_type (fullpath);
+
+            stats_event_hidden (finfo->mount, "file", fullpath, STATS_HIDDEN);
+            fh->format = calloc (1, sizeof (format_plugin_t));
+            fh->format->type = format_get_type (contenttype);
+            free (contenttype);
+            fh->format->mount = fh->finfo.mount;
+            if (format_get_plugin (fh->format) < 0)
+            {
+                avl_tree_unlock (fh_cache);
+                free (fullpath);
+                free (fh);
+                return NULL;
+            }
+            if (fh->format->create_client_data && client->format_data == NULL)
+            {
+                fh->format->create_client_data (fh->format, client);
+                client->check_buffer = fh->format->write_buf_to_client;
+            }
+        }
         free (fullpath);
     }
     thread_mutex_create (&fh->lock);
     thread_mutex_lock (&fh->lock);
     fh->refcount = 1;
+    if (client)
+    {
+        if (finfo->mount && (finfo->flags & FS_FALLBACK))
+            stats_event_hidden (fh->finfo.mount, "listeners", "1", STATS_HIDDEN);
+        fh->clients = client;
+        client->next = NULL;
+    }
     fh->finfo.mount = strdup (finfo->mount);
     if (finfo->fallback)
         fh->finfo.fallback = strdup (finfo->fallback);
@@ -245,16 +330,103 @@
 }
 
 
+static int fill_http_headers (client_t *client, const char *path, struct stat *file_buf)
+{
+    char *type;
+    off_t content_length = 0;
+    const char *range = httpp_getvar (client->parser, "range");
+    refbuf_t *ref = client->refbuf;
+
+
+    if (file_buf)
+        content_length = file_buf->st_size;
+    /* full http range handling is currently not done but we deal with the common case */
+    if (range)
+    {
+        off_t new_content_len = 0, rangenumber = 0;
+        int ret = 0;
+
+        if (strncasecmp (range, "bytes=", 6) == 0)
+            ret = sscanf (range+6, "%" SCN_OFF_T "-", &rangenumber);
+
+        if (ret == 1 && rangenumber>=0 && rangenumber < content_length)
+        {
+            /* Date: is required on all HTTP1.1 responses */
+            char currenttime[50];
+            time_t now;
+            int strflen;
+            struct tm result;
+            off_t endpos;
+            fh_node * fh = client->shared_data;
+
+            ret = fseeko (fh->fp, rangenumber, SEEK_SET);
+            if (ret == -1)
+                return -1;
+
+            client->intro_offset = rangenumber;
+            new_content_len = content_length - rangenumber;
+            endpos = rangenumber + new_content_len - 1;
+            if (endpos < 0)
+                endpos = 0;
+
+            now = client->worker->current_time.tv_sec;
+            strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT",
+                    gmtime_r (&now, &result));
+            client->respcode = 206;
+            type = fserve_content_type (path);
+            snprintf (ref->data, BUFSIZE,
+                    "HTTP/1.1 206 Partial Content\r\n"
+                    "Date: %s\r\n"
+                    "Accept-Ranges: bytes\r\n"
+                    "Content-Length: %" PRI_OFF_T "\r\n"
+                    "Content-Range: bytes %" PRI_OFF_T
+                    "-%" PRI_OFF_T 
+                    "/%" PRI_OFF_T "\r\n"
+                    "Content-Type: %s\r\n\r\n",
+                    currenttime,
+                    new_content_len,
+                    rangenumber,
+                    endpos,
+                    content_length,
+                    type);
+        }
+        else
+            return -1;
+    }
+    else
+    {
+        type = fserve_content_type (path);
+        client->respcode = 200;
+        if (content_length)
+            snprintf (ref->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Accept-Ranges: bytes\r\n"
+                    "Content-Type: %s\r\n"
+                    "Content-Length: %" PRI_OFF_T "\r\n"
+                    "\r\n",
+                    type,
+                    content_length);
+        else
+            snprintf (ref->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: %s\r\n"
+                    "\r\n",
+                    type);
+    }
+    free (type);
+    client->refbuf->len = strlen (ref->data);
+    client->pos = 0;
+    ref->flags |= WRITE_BLOCK_GENERIC;
+    return 0;
+}
+
+
 /* client has requested a file, so check for it and send the file.  Do not
  * refer to the client_t afterwards.  return 0 for success, -1 on error.
  */
 int fserve_client_create (client_t *httpclient, const char *path)
 {
     struct stat file_buf;
-    const char *range = NULL;
-    off_t new_content_len = 0;
-    off_t rangenumber = 0, content_length;
-    int ret = 0;
     char *fullpath;
     int m3u_requested = 0, m3u_file_available = 1;
     int xspf_requested = 0, xspf_file_available = 1;
@@ -378,7 +550,7 @@
     finfo.fallback = NULL;
     finfo.limit = 0;
 
-    fh = open_fh (&finfo);
+    fh = open_fh (&finfo, httpclient);
     if (fh == NULL)
     {
         WARN1 ("Problem accessing file \"%s\"", fullpath);
@@ -388,101 +560,19 @@
     }
     free (fullpath);
 
-    content_length = file_buf.st_size;
-    range = httpp_getvar (httpclient->parser, "range");
-
-    do
+    httpclient->intro_offset = 0;
+    httpclient->shared_data = fh;
+    if (fill_http_headers (httpclient, path, &file_buf) < 0)
     {
-        int bytes;
+        thread_mutex_unlock (&fh->lock);
+        client_send_416 (httpclient);
+        return -1;
+    }
 
-        httpclient->intro_offset = 0;
-        /* full http range handling is currently not done but we deal with the common case */
-        if (range)
-        {
-            ret = 0;
-            if (strncasecmp (range, "bytes=", 6) == 0)
-                ret = sscanf (range+6, "%" SCN_OFF_T "-", &rangenumber);
-
-            if (ret == 1 && rangenumber>=0 && rangenumber < content_length)
-            {
-                /* Date: is required on all HTTP1.1 responses */
-                char currenttime[50];
-                time_t now;
-                int strflen;
-                struct tm result;
-                off_t endpos;
-                char *type;
-
-                ret = fseeko (fh->fp, rangenumber, SEEK_SET);
-                if (ret == -1)
-                    break;
-
-                httpclient->intro_offset = rangenumber;
-                new_content_len = content_length - rangenumber;
-                endpos = rangenumber + new_content_len - 1;
-                if (endpos < 0)
-                    endpos = 0;
-                
-                time(&now);
-                strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT",
-                                   gmtime_r (&now, &result));
-                httpclient->respcode = 206;
-                type = fserve_content_type (path);
-                bytes = snprintf (httpclient->refbuf->data, BUFSIZE,
-                    "HTTP/1.1 206 Partial Content\r\n"
-                    "Date: %s\r\n"
-                    "Accept-Ranges: bytes\r\n"
-                    "Content-Length: %" PRI_OFF_T "\r\n"
-                    "Content-Range: bytes %" PRI_OFF_T
-                    "-%" PRI_OFF_T 
-                    "/%" PRI_OFF_T "\r\n"
-                    "Content-Type: %s\r\n\r\n",
-                    currenttime,
-                    new_content_len,
-                    rangenumber,
-                    endpos,
-                    content_length,
-                    type);
-                free (type);
-            }
-            else
-                break;
-        }
-        else
-        {
-            char *type = fserve_content_type (path);
-            httpclient->respcode = 200;
-            if (httpclient->flags & CLIENT_NO_CONTENT_LENGTH)
-                bytes = snprintf (httpclient->refbuf->data, BUFSIZE,
-                        "HTTP/1.0 200 OK\r\n"
-                        "Content-Type: %s\r\n"
-                        "\r\n",
-                        type);
-            else
-                bytes = snprintf (httpclient->refbuf->data, BUFSIZE,
-                        "HTTP/1.0 200 OK\r\n"
-                        "Accept-Ranges: bytes\r\n"
-                        "Content-Type: %s\r\n"
-                        "Content-Length: %" PRI_OFF_T "\r\n"
-                        "\r\n",
-                        type,
-                        content_length);
-            free (type);
-        }
-        httpclient->refbuf->len = bytes;
-        httpclient->pos = 0;
-        httpclient->shared_data = fh;
-
-        stats_event_inc (NULL, "file_connections");
-        thread_mutex_unlock (&fh->lock);
-        fserve_setup_client_fb (httpclient, NULL);
-        return 0;
-    } while (0);
+    stats_event_inc (NULL, "file_connections");
     thread_mutex_unlock (&fh->lock);
-    /* If we run into any issues with the ranges
-       we fallback to a normal/non-range request */
-    client_send_416 (httpclient);
-    return -1;
+    fserve_setup_client_fb (httpclient, NULL);
+    return 0;
 }
 
 // fh must be locked before calling this
@@ -509,12 +599,20 @@
     avl_tree_unlock (fh_cache);
 }
 
+
 static void file_release (client_t *client)
 {
     fh_node *fh = client->shared_data;
     const char *mount = httpp_getvar (client->parser, HTTPP_VAR_URI);
 
-    rate_free (client->out_bitrate);
+    if (fh)
+    {
+        thread_mutex_lock (&fh->lock);
+        if (fh->finfo.flags & (FS_FALLBACK|FS_JINGLE))
+            stats_event_dec (NULL, "listeners");
+        remove_from_fh (fh, client);
+        fh_release (fh);
+    }
     if (client->respcode == 200)
     {
         ice_config_t *config = config_get_config ();
@@ -528,25 +626,19 @@
         client_destroy (client);
     }
     global_reduce_bitrate_sampling (global.out_bitrate);
-    if (fh)
-    {
-        thread_mutex_lock (&fh->lock);
-        if (fh->finfo.flags & (FS_FALLBACK|FS_JINGLE))
-            stats_event_dec (NULL, "listeners");
-        fh_release (fh);
-    }
 }
 
 
-struct _client_functions file_content_ops =
+struct _client_functions buffer_content_ops =
 {
-    file_send,
+    prefile_send,
     file_release
 };
 
-struct _client_functions buffer_content_ops =
+
+struct _client_functions file_content_ops =
 {
-    prefile_send,
+    file_send,
     file_release
 };
 
@@ -558,10 +650,9 @@
 
     refbuf_release (client->refbuf);
     client->refbuf = NULL;
-    rate_free (client->out_bitrate);
-    client->out_bitrate = NULL;
     client->shared_data = NULL;
     thread_mutex_lock (&fh->lock);
+    remove_from_fh (fh, client);
     f.flags = fh->finfo.flags;
     f.limit = fh->finfo.limit;
     f.mount = fh->finfo.fallback;
@@ -571,6 +662,7 @@
     fh_release (fh);
 }
 
+struct _client_functions throttled_file_content_ops;
 
 static int prefile_send (client_t *client)
 {
@@ -596,13 +688,18 @@
                 {
                     if (fh->fp) // is there a file to read from
                     {
-                        int len = fh->finfo.limit ? 1400 : 4096;
-                        refbuf_t *r = refbuf_new (len);
+                        int len = 8192;
+                        if (fh->finfo.flags & FS_FALLBACK)
+                        {
+                            len = 1400;
+                            client->ops = &throttled_file_content_ops;
+                        }
+                        else
+                            client->ops = &file_content_ops;
                         refbuf_release (client->refbuf);
-                        client->refbuf = r;
+                        client->refbuf = refbuf_new(len);
                         client->pos = len;
-                        client->ops = &file_content_ops;
-                        return 1;
+                        return 0;
                     }
                 }
                 if (client->respcode)
@@ -621,7 +718,10 @@
             }
             client->pos = 0;
         }
-        bytes = format_generic_write_to_client (client);
+        if (refbuf->flags & WRITE_BLOCK_GENERIC)
+            bytes = format_generic_write_to_client (client);
+        else 
+            bytes = client->check_buffer (client);
         if (bytes < 0)
         {
             client->schedule_ms = client->worker->time_ms + 300;
@@ -636,102 +736,172 @@
     return 0;
 }
 
+static int read_file (client_t *client, int blksize)
+{
+    refbuf_t *refbuf = client->refbuf;
+    fh_node *fh = client->shared_data;
+    int bytes = 0;
 
+    switch (fseeko (fh->fp, client->intro_offset, SEEK_SET))
+    {
+        case -1:
+            client->connection.error = 1;
+            break;
+        default:
+            bytes = fread (refbuf->data, 1, blksize, fh->fp);
+            if (bytes > 0)
+            {
+                refbuf->len = bytes;
+                client->intro_offset += bytes;
+            }
+    }
+    return bytes;
+}
+
+
+/* fast send routine */
 static int file_send (client_t *client)
 {
     refbuf_t *refbuf = client->refbuf;
-    int loop = 6, bytes, written = 0;
+    int loop = 6, bytes, written = 0, ret = 0;
     fh_node *fh = client->shared_data;
+    time_t now = client->worker->current_time.tv_sec;
 
-    if (client->connection.discon_time &&
-            client->worker->current_time.tv_sec >= client->connection.discon_time)
-        return -1;
-    while (loop)
+    client->schedule_ms = client->worker->time_ms;
+    while (loop && written < 30000)
     {
         loop--;
         if (fserve_running == 0 || client->connection.error)
             return -1;
-        if (fh->finfo.limit)
-        {
-            long rate = rate_avg (client->out_bitrate);
-            if (rate == 0) loop = 0;
-            if (fh->finfo.limit < rate)
-            {
-                rate_add (client->out_bitrate, 0, client->worker->time_ms);
-                client->schedule_ms = client->worker->time_ms + 150;
-                return 0;
-            }
-        }
+        if (client->connection.discon_time && now >= client->connection.discon_time)
+            return -1;
         if (client->pos == refbuf->len)
         {
-            bytes = 0;
-            if (fh->finfo.fallback)
-            {
-                fserve_move_listener (client);
-                return 0;
-            }
-            if (fh->fp)
-            {
-                thread_mutex_lock (&fh->lock);
-                if (fseeko (fh->fp, client->intro_offset, SEEK_SET) == 0 &&
-                        (bytes = fread (refbuf->data, 1, refbuf->len, fh->fp)) > 0)
-                {
-                    refbuf->len = bytes;
-                    client->intro_offset += bytes;
-                }
-                thread_mutex_unlock (&fh->lock);
-            }
-            if (bytes == 0)
+            thread_mutex_lock (&fh->lock);
+            ret = read_file (client, 8192);
+            thread_mutex_unlock (&fh->lock);
+            if (ret == 0)
                 return -1;
             client->pos = 0;
         }
         bytes = client->check_buffer (client);
         if (bytes < 0)
+            break;
+        written += bytes;
+        client->schedule_ms += 3;
+    }
+    return 0;
+}
+
+
+/* send routine for files sent at a target bitrate, eg fallback files. */
+static int throttled_file_send (client_t *client)
+{
+    refbuf_t *refbuf = client->refbuf;
+    int  bytes;
+    fh_node *fh = client->shared_data;
+    time_t now = client->worker->current_time.tv_sec;
+    unsigned long secs = now - client->timer_start; 
+    unsigned int  rate = secs ? ((client->counter+1400)/secs) : 0;
+
+    if (fserve_running == 0 || client->connection.error)
+        return -1;
+    if (client->connection.discon_time && now >= client->connection.discon_time)
+        return -1;
+    if (fh->finfo.fallback)
+    {
+        fserve_move_listener (client);
+        return 0;
+    }
+    thread_mutex_lock (&fh->lock);
+    if (rate >= fh->finfo.limit)
+    {
+        client->schedule_ms = client->worker->time_ms + (1000*(rate - fh->finfo.limit))/fh->finfo.limit;
+        rate_add (fh->format->out_bitrate, 0, client->worker->time_ms);
+        thread_mutex_unlock (&fh->lock);
+        global_add_bitrates (global.out_bitrate, 0, client->worker->time_ms);
+        return 0;
+    }
+    if (fh->stats_update <= now)
+    {
+        stats_event_args (fh->finfo.mount, "outgoing_kbitrate", "%ld",
+                            (8 * rate_avg (fh->format->out_bitrate))/1024);
+        fh->stats_update = now + 5;
+    }
+    if (client->pos == refbuf->len)
+    {
+        if (read_file (client, 1400) == 0)
         {
-            client->schedule_ms = client->worker->time_ms + 300;
+            /* loop fallback file  */
+            thread_mutex_unlock (&fh->lock);
+            client->intro_offset = 0;
+            client->schedule_ms = client->worker->time_ms + 150;
             return 0;
         }
-        written += bytes;
-        global_add_bitrates (global.out_bitrate, bytes, client->worker->time_ms);
-        if (fh->finfo.limit)
-            rate_add (client->out_bitrate, bytes, client->worker->time_ms);
-        if (written > 30000)
-            break;
+        client->pos = 0;
     }
-    client->schedule_ms = client->worker->time_ms + 150;
-    return 1;
+    bytes = client->check_buffer (client);
+    if (bytes < 0)
+        bytes = 0;
+    rate_add (fh->format->out_bitrate, bytes, client->worker->time_ms);
+    thread_mutex_unlock (&fh->lock);
+    global_add_bitrates (global.out_bitrate, bytes, client->worker->time_ms);
+    client->counter += bytes;
+    client->schedule_ms = client->worker->time_ms + (1000/(fh->finfo.limit/1400*2));
+    return 0;
 }
 
 
-void fserve_setup_client_fb (client_t *client, fbinfo *finfo)
+struct _client_functions throttled_file_content_ops =
 {
-    client->ops = &buffer_content_ops;
+    throttled_file_send,
+    file_release
+};
+
+
+/* return 0 for success, 1 for fallback invalid */
+int fserve_setup_client_fb (client_t *client, fbinfo *finfo)
+{
     if (finfo)
     {
-        fh_node *fh = open_fh (finfo);
+        fh_node *fh;
+        if (finfo->flags & FS_FALLBACK && finfo->limit == 0)
+            return 1;
+        fh = open_fh (finfo, client);
+        if (fh == NULL)
+            return 1;
         client->shared_data = fh;
-        if (fh)
+
+        if (fh->finfo.limit)
         {
-            if (fh->finfo.limit)
-                client->out_bitrate = rate_setup (50,1000);
-            thread_mutex_unlock (&fh->lock);
+            client->timer_start = client->worker->current_time.tv_sec;
+            if (client->connection.sent_bytes == 0)
+                client->timer_start -= 2;
+            client->counter = 0;
+            fh->stats_update = client->timer_start + 5;
+            fh->format->out_bitrate = rate_setup (10000, 1000);
+            global_reduce_bitrate_sampling (global.out_bitrate);
         }
+        thread_mutex_unlock (&fh->lock);
+        if (client->respcode == 0)
+            fill_http_headers (client, finfo->mount, NULL);
     }
     else
-    {
         client->check_buffer = format_generic_write_to_client;
-    }
+
+    client->ops = &buffer_content_ops;
     client->flags &= ~CLIENT_HAS_INTRO_CONTENT;
     client->intro_offset = 0;
     if (client->flags & CLIENT_ACTIVE)
         client->schedule_ms = client->worker->time_ms;
     else
     {
+        thread_mutex_lock (&client->worker->lock);
         client->flags |= CLIENT_ACTIVE;
-        thread_mutex_lock (&client->worker->lock);
         thread_cond_signal (&client->worker->cond);
         thread_mutex_unlock (&client->worker->lock);
     }
+    return 0;
 }
 
 
@@ -761,6 +931,7 @@
         char *tmp = result->finfo.fallback;
         result->finfo.fallback = strdup (dest);
         free (tmp);
+        INFO2 ("move clients from %s to %s", mount, dest);
     }
     avl_tree_unlock (fh_cache);
 }
@@ -852,38 +1023,141 @@
 }
 
 
-#if 0
-/* generate xml list containing listener details for clients attached via the file
- * serving engine.
- */
-xmlDocPtr command_show_listeners(client_t *client, source_t *source,
-        int response)
+void fserve_kill_client (client_t *client, const char *mount, int response)
 {
+    int c = 2, id;
+    fbinfo finfo;
     xmlDocPtr doc;
+    xmlNodePtr node;
+    const char *idtext, *v = "0";
+    char buf[50];
+
+    finfo.flags = FS_NORMAL;
+    finfo.mount = (char*)mount;
+    finfo.limit = 0;
+    finfo.fallback = NULL;
+
+    idtext = httpp_get_query_param (client->parser, "id");
+    if (idtext == NULL)
+    {
+        client_send_400 (client, "missing parameter id");
+        return;
+    }
+    id = atoi(idtext);
+
+    doc = xmlNewDoc(XMLSTR("1.0"));
+    node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
+    xmlDocSetRootElement(doc, node);
+    snprintf (buf, sizeof(buf), "Client %d not found", id);
+
+    while (c)
+    {
+        fh_node *fh = open_fh (&finfo, NULL);
+        if (fh)
+        {
+            client_t *listener = fh->clients;
+
+            while (listener)
+            {
+                if (listener->connection.id == id)
+                {
+                    listener->connection.error = 1;
+                    snprintf (buf, sizeof(buf), "Client %d removed", id);
+                    v = "1";
+                    break;
+                }
+                listener = listener->next;
+            }
+            fh_release (fh);
+            break;
+        }
+        c--;
+        finfo.flags = FS_FALLBACK;
+    }
+    xmlNewChild (node, NULL, XMLSTR("message"), XMLSTR(buf));
+    xmlNewChild (node, NULL, XMLSTR("return"), XMLSTR(v));
+    admin_send_response (doc, client, response, "response.xsl");
+    xmlFreeDoc(doc);
+}
+
+
+void fserve_list_clients (client_t *client, const char *mount, int response, int show_listeners)
+{
+    int c = 2;
+    unsigned int entries = 0;
+    const char *type = httpp_get_query_param (client->parser, "type");
+    fbinfo finfo;
+    xmlDocPtr doc;
     xmlNodePtr node, srcnode;
-    unsigned long id = -1;
-    char *ID_str = NULL;
-    char buf[22];
+    char buf[100];
 
+    finfo.flags = FS_NORMAL;
+    if (type && strcmp (type, "fallback") == 0)
+    {
+        finfo.flags = FS_FALLBACK;
+        c = 1;
+    }
+    finfo.mount = (char*)mount;
+    finfo.limit = 0;
+    finfo.fallback = NULL;
+
     doc = xmlNewDoc(XMLSTR("1.0"));
     node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
     xmlDocSetRootElement(doc, node);
+    srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL);
+    xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(mount));
 
+    while (c)
     {
-        client_t *listener;
-        thread_mutex_lock (&source->lock);
+        fh_node *fh = open_fh (&finfo, NULL);
+        if (fh)
+        {
+            client_t *listener = fh->clients;
 
-        listener = source->active_clients;
-        while (listener)
-        {
-            add_listener_node (srcnode, listener);
-            listener = listener->next;
+            while (listener)
+            {
+                if (show_listeners)
+                {
+                    xmlNodePtr node = xmlNewChild (srcnode, NULL, XMLSTR("listener"), NULL);
+                    const char *useragent;
+                    snprintf (buf, sizeof (buf), "%lu", listener->connection.id);
+                    xmlSetProp (node, XMLSTR("id"), XMLSTR(buf));
+
+                    xmlNewChild (node, NULL, XMLSTR("ip"), XMLSTR(listener->connection.ip));
+                    useragent = httpp_getvar (listener->parser, "user-agent");
+                    if (useragent)
+                    {
+                        xmlChar *str = xmlEncodeEntitiesReentrant (srcnode->doc, XMLSTR(useragent));
+                        xmlNewChild (node, NULL, XMLSTR("useragent"), str);
+                        xmlFree (str);
+                    }
+                    xmlNewChild (node, NULL, XMLSTR("lag"), XMLSTR( "0"));
+                    snprintf (buf, sizeof (buf), "%lu",
+                            (unsigned long)(listener->worker->current_time.tv_sec - listener->connection.con_time));
+                    xmlNewChild (node, NULL, XMLSTR("connected"), XMLSTR(buf));
+                    if (listener->username)
+                    {
+                        xmlChar *str = xmlEncodeEntitiesReentrant (srcnode->doc, XMLSTR(listener->username));
+                        xmlNewChild (node, NULL, XMLSTR("username"), str);
+                        xmlFree (str);
+                    }
+                }
+
+                entries++;
+                listener = listener->next;
+            }
+            fh_release (fh);
         }
-        thread_mutex_unlock (&source->lock);
+        c--;
+        finfo.flags = FS_FALLBACK;
     }
-
-    admin_send_response(doc, client, response, "listclients.xsl");
+    if (entries)
+    {
+        snprintf (buf, sizeof(buf), "%u", entries);
+        xmlNewChild(srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));
+        admin_send_response (doc, client, response, "listclients.xsl");
+    }
+    else
+        client_send_400 (client, "mount does not exist");
     xmlFreeDoc(doc);
 }
-
-#endif

Modified: icecast/branches/kh/icecast/src/fserve.h
===================================================================
--- icecast/branches/kh/icecast/src/fserve.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/fserve.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -38,8 +38,10 @@
 void fserve_recheck_mime_types (ice_config_t *config);
 
 void fserve_setup_client (client_t *client, const char *mount);
-void fserve_setup_client_fb (client_t *client, fbinfo *finfo);
+int  fserve_setup_client_fb (client_t *client, fbinfo *finfo);
 void fserve_set_override (const char *mount, const char *dest);
+void fserve_list_clients (client_t *client, const char *mount, int response, int show_listeners);
+void fserve_kill_client (client_t *client, const char *mount, int response);
 
 #endif
 

Modified: icecast/branches/kh/icecast/src/global.c
===================================================================
--- icecast/branches/kh/icecast/src/global.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/global.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -42,10 +42,13 @@
     global.clients = 0;
     global.sources = 0;
     global.source_tree = avl_tree_new(source_compare_sources, NULL);
+#ifdef MY_ALLOC
+    global.alloc_tree = avl_tree_new(compare_allocs, NULL);
+#endif
     thread_mutex_create(&_global_mutex);
     thread_spin_create (&global.spinlock);
     thread_rwlock_create (&global.shutdown_lock);
-    global.out_bitrate = rate_setup (151, 1000);
+    global.out_bitrate = rate_setup (10000, 1000);
 }
 
 void global_shutdown(void)
@@ -54,6 +57,9 @@
     thread_spin_destroy (&global.spinlock);
     thread_rwlock_destroy (&global.shutdown_lock);
     avl_tree_free(global.source_tree, NULL);
+#ifdef MY_ALLOC
+    avl_tree_free(global.alloc_tree, free_alloc_node);
+#endif
     rate_free (global.out_bitrate);
     global.out_bitrate = NULL;
 }
@@ -78,7 +84,7 @@
 void global_reduce_bitrate_sampling (struct rate_calc *rate)
 {
     thread_spin_lock (&global.spinlock);
-    rate_reduce (rate, 2);
+    rate_reduce (rate, 500);
     thread_spin_unlock (&global.spinlock);
 }
 
@@ -91,3 +97,108 @@
     return v;
 }
 
+#ifdef MY_ALLOC
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+int compare_allocs(void *arg, void *a, void *b)
+{
+    alloc_node  *nodea = (alloc_node  *)a;
+    alloc_node  *nodeb = (alloc_node  *)b;
+
+    return strcmp(nodea->name, nodeb->name);
+}
+
+typedef struct 
+{
+    alloc_node *info;
+    size_t len;
+} allocheader;
+
+void *my_calloc (const char *file, int line, size_t num, size_t size)
+{
+    alloc_node match, *result;
+    snprintf (match.name, sizeof (match.name), "%s:%d", file, line);
+
+    avl_tree_wlock (global.alloc_tree);
+    if (avl_get_by_key (global.alloc_tree, &match, (void**)&result) == 0)
+    {
+        allocheader *block = calloc (1, (num*size)+sizeof(allocheader));
+        result->count++;
+        result->allocated += (num*size);
+        block->info = result;
+        block->len = num*size;
+        avl_tree_unlock (global.alloc_tree);
+        return block+1;
+    }
+    result = calloc (1, sizeof(alloc_node));
+    if (result)
+    {
+        allocheader *block = calloc (1, (num*size)+sizeof(allocheader));
+        snprintf (result->name, sizeof (result->name), "%s:%d", file, line);
+        result->count = 1;
+        result->allocated = (num * size);
+        avl_insert (global.alloc_tree, result);
+        block->info = result;
+        block->len = num*size;
+        avl_tree_unlock (global.alloc_tree);
+        return block+1;
+    }
+    avl_tree_unlock (global.alloc_tree);
+    return NULL;
+}
+int free_alloc_node(void *key)
+{
+    alloc_node *node = (alloc_node *)key;
+    memset (node, 255, sizeof(*node));
+    free(node);
+    return 1;
+}
+
+void my_free (void *freeblock)
+{
+    allocheader *block;
+    alloc_node *info;
+    if (freeblock == NULL)
+        return;
+    block = (allocheader*)freeblock -1;
+    info = block->info;
+    avl_tree_wlock (global.alloc_tree);
+    info->count--;
+    info->allocated -= block->len;
+    avl_tree_unlock (global.alloc_tree);
+    free (block);
+}
+void *my_realloc (const char *file, int line, void *ptr, size_t size)
+{
+    allocheader *block, *newblock;
+    alloc_node *info;
+
+    if (ptr == NULL)
+        return my_calloc (file, line, 1, size);
+    if (size == 0)
+    {
+        my_free (ptr);
+        return NULL;
+    }
+    block = (allocheader*)ptr -1;
+    avl_tree_wlock (global.alloc_tree);
+    newblock = realloc (block, sizeof (allocheader)+size);
+    info = newblock->info;
+    info->allocated -= newblock->len;
+    info->allocated += size;
+    newblock->len = size;
+    avl_tree_unlock (global.alloc_tree);
+    return newblock+1;
+}
+char *my_strdup(const char *file, int line, const char *s)
+{
+    int len = strlen (s) +1;
+    char *str = my_calloc (file, line, 1, len);
+    strcpy (str, s);
+    return str;
+}
+#endif

Modified: icecast/branches/kh/icecast/src/global.h
===================================================================
--- icecast/branches/kh/icecast/src/global.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/global.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -41,6 +41,10 @@
     avl_tree *source_tree;
     rwlock_t shutdown_lock;
 
+#ifdef MY_ALLOC
+    avl_tree *alloc_tree;
+#endif
+
     /* for locally defined relays */
     struct _relay_server *relays;
     /* relays retrieved from master */
@@ -55,6 +59,27 @@
     cond_t shutdown_cond;
 } ice_global_t;
 
+#ifdef MY_ALLOC
+#define calloc(x,y) my_calloc(__func__,__LINE__,x,y)
+#define malloc(x) my_calloc(__func__,__LINE__,1,x)
+#define realloc(x,y) my_realloc(__func__,__LINE__,x,y)
+#define free(x) my_free(x)
+#define strdup(x) my_strdup(__func__,__LINE__,x)
+char *my_strdup (const char *file, int line, const char *s);
+void *my_calloc (const char *file, int line, size_t num, size_t size);
+void *my_realloc (const char *file, int line, void *ptr, size_t size);
+void my_free (void *freeblock);
+int compare_allocs(void *arg, void *a, void *b);
+int free_alloc_node(void *key);
+
+typedef struct {
+    char name[54];
+    int count;
+    int allocated;
+} alloc_node;
+
+#endif
+
 extern ice_global_t global;
 
 void global_initialize(void);

Modified: icecast/branches/kh/icecast/src/refbuf.c
===================================================================
--- icecast/branches/kh/icecast/src/refbuf.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/refbuf.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -28,6 +28,7 @@
 #define CATMODULE "refbuf"
 
 #include "logging.h"
+#include "global.h"
 
 
 void refbuf_initialize(void)

Modified: icecast/branches/kh/icecast/src/refbuf.h
===================================================================
--- icecast/branches/kh/icecast/src/refbuf.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/refbuf.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -40,5 +40,7 @@
 
 #define PER_CLIENT_REFBUF_SIZE  4096
 
+#define WRITE_BLOCK_GENERIC     01000
+
 #endif  /* __REFBUF_H__ */
 

Modified: icecast/branches/kh/icecast/src/sighandler.c
===================================================================
--- icecast/branches/kh/icecast/src/sighandler.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/sighandler.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -61,8 +61,6 @@
 
 void _sig_die(int signo)
 {
-    INFO1("Caught signal %d, shutting down...", signo);
-
     /* inform the server to start shutting down */
     global.running = ICE_HALTING;
 }

Modified: icecast/branches/kh/icecast/src/slave.c
===================================================================
--- icecast/branches/kh/icecast/src/slave.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/slave.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -147,6 +147,7 @@
             if (from->bind)
                 to->bind = (char *)xmlCharStrdup (from->bind);
             to->port = from->port;
+            to->timeout = from->timeout;
             *insert = to;
             from = from->next;
             insert = &to->next;
@@ -175,6 +176,7 @@
 {
     update_all_mounts = 1;
     update_settings = 1;
+    streamlist_check = 0;
 }
 
 
@@ -340,7 +342,7 @@
         else
             INFO3 ("connecting to %s:%d for %s", server, port, relay->localmount);
 
-        streamsock = sock_connect_wto_bind (server, port, bind, 10);
+        streamsock = sock_connect_wto_bind (server, port, bind, master->timeout);
         if (streamsock == SOCK_ERROR)
         {
             WARN3 ("Failed to connect to %s:%d for %s", server, port, relay->localmount);
@@ -448,8 +450,6 @@
     source_t *src = relay->source;
     relay_server_master *master = relay->masters;
     client_t *client = src->client;
-    mount_proxy *mountinfo;
-    ice_config_t *config;
 
     INFO1("Starting relayed source at mountpoint \"%s\"", relay->localmount);
     thread_rwlock_rlock (&global.shutdown_lock);
@@ -462,8 +462,9 @@
         ret = open_relay_connection (client, relay, master);
         thread_mutex_lock (&src->lock);
 
-        if (ret < 0)
+        if (global.running == ICE_RUNNING && ret < 0)
             continue;
+        source_clear_source (src); // clear any old data
         src->parser = client->parser;
 
         if (connection_complete_source (src, 0) < 0)
@@ -481,7 +482,10 @@
         thread_spin_lock (&relay_start_lock);
         relays_connecting--;
         thread_spin_unlock (&relay_start_lock);
+
+        thread_mutex_lock (&client->worker->lock);
         thread_cond_signal (&client->worker->cond);
+        thread_mutex_unlock (&client->worker->lock);
 
         return NULL;
     } while ((master = master->next));
@@ -497,64 +501,70 @@
         httpp_destroy (client->parser);
     client->parser = NULL;
 
-    config = config_get_config();
-    mountinfo = config_find_mount (config, src->mount);
-    if (mountinfo && mountinfo->fallback_mount && strcmp (src->mount, mountinfo->fallback_mount) != 0)
+    if (global.running == ICE_RUNNING)
     {
-        int left_on = 0;
-        client_t *leave_on = NULL, *check_clients, *last = NULL;
-        INFO1 ("failed relay, fallback to %s", mountinfo->fallback_mount);
-        check_clients = src->client_list;
-        src->client_list = NULL;
-        src->listeners = 0;
-        while (check_clients)
+        ice_config_t *config = config_get_config();
+        mount_proxy *mountinfo = config_find_mount (config, src->mount);
+
+        DEBUG1 ("checking for fallback on %s", src->mount);
+        if (mountinfo && mountinfo->fallback_mount && strcmp (src->mount, mountinfo->fallback_mount) != 0)
         {
-            client_t *to_move = check_clients;
-            check_clients = to_move->next;
-            if (to_move->flags & CLIENT_IS_SLAVE)
+            int left_on = 0;
+            client_t *leave_list = NULL, *check_clients, **leave_last = &leave_list;
+            INFO1 ("failed relay, fallback to %s", mountinfo->fallback_mount);
+            check_clients = src->client_list;
+            src->client_list = NULL;
+            src->listeners = 0;
+            while (check_clients)
             {
-                if (leave_on == NULL) last = to_move;
-                to_move->next = leave_on;
-                leave_on = to_move;
-                left_on++;
-            }
-            else
-            {
+                client_t *to_move = check_clients;
+                int not_moved;
                 fbinfo f;
+
+                check_clients = to_move->next;
+
                 f.mount = mountinfo->fallback_mount;
-                f.flags = FS_NORMAL;
+                f.flags = FS_FALLBACK;
                 f.fallback = NULL;
                 if (src->format)
                     f.limit = rate_avg (src->format->in_bitrate);
-                else
-                    f.limit = src->limit_rate;
+                else 
+                    f.limit = mountinfo->limit_rate;
                 thread_mutex_unlock (&src->lock);
-                move_listener (to_move, &f);
+                not_moved = move_listener (to_move, &f);
                 thread_mutex_lock (&src->lock);
+                if (not_moved)
+                {
+                    *leave_last = to_move;
+                    leave_last = &to_move->next;
+                    left_on++;
+                }
             }
+            /* it is possible that listeners could of been moved here by now */
+            src->listeners += left_on;
+            *leave_last = src->client_list;
+            src->client_list = leave_list;
         }
-        /* it is possible that listeners could of been moved here by now */
-        src->listeners += left_on;
-        if (last)
-        {
-            last->next = src->client_list;
-            src->client_list = leave_on;
-        }
+        config_release_config();
     }
-    config_release_config();
 
-    INFO2 ("listener count still on %s is %d", src->mount, src->listeners);
+    INFO2 ("listener count remaining on %s is %d", src->mount, src->listeners);
     source_clear_listeners (src);
-    source_clear_source (src);
+    if (relay->on_demand == 0 || global.running != ICE_RUNNING)
+        source_clear_source (src);
     thread_mutex_unlock (&src->lock);
-    relay->start = client->worker->current_time.tv_sec + relay->interval;
-    client->schedule_ms = timing_get_time() + 1000;
-    client->flags |= CLIENT_ACTIVE;
 
     thread_spin_lock (&relay_start_lock);
     relays_connecting--;
     thread_spin_unlock (&relay_start_lock);
+
+    thread_mutex_lock (&client->worker->lock);
+    client->schedule_ms = timing_get_time();
+    relay->start = (client->schedule_ms/1000) + relay->interval;
+    client->schedule_ms += 1000;
+    client->flags |= CLIENT_ACTIVE;
     thread_cond_signal (&client->worker->cond);
+    thread_mutex_unlock (&client->worker->lock);
     thread_rwlock_unlock (&global.shutdown_lock);
     return NULL;
 }
@@ -666,22 +676,39 @@
         {
             /* break out if keeping relay */
             if (strcmp (relay->localmount, existing_relay->localmount) == 0)
-                if (relay_has_changed (relay, existing_relay) == 0)
-                    break;
-            existing_p = &existing_relay->next;
-            existing_relay = existing_relay->next;
+            {
+                relay_server *new = existing_relay;
+
+                if (global.running == ICE_RUNNING && relay_has_changed (relay, existing_relay))
+                {
+                    client_t *client = existing_relay->source->client;
+                    new = relay_copy (relay);
+                    thread_mutex_lock (&client->worker->lock);
+                    existing_relay->cleanup = 0;
+                    client->shared_data = new;
+                    new->source = existing_relay->source;
+                    existing_relay->source = NULL;
+                    new->running = 1;
+                    thread_mutex_unlock (&client->worker->lock);
+                    INFO1 ("relay details changed on \"%s\", restarting", new->localmount);
+                }
+                else
+                    *existing_p = existing_relay->next;
+                new->next = new_list;
+                new_list = new;
+                break;
+            }
+            else
+                existing_p = &existing_relay->next;
+            existing_relay = *existing_p;
         }
         if (existing_relay == NULL)
         {
             /* new one, copy and insert */
             existing_relay = relay_copy (relay);
+            existing_relay->next = new_list;
+            new_list = existing_relay;
         }
-        else
-        {
-            *existing_p = existing_relay->next;
-        }
-        existing_relay->next = new_list;
-        new_list = existing_relay;
         relay = relay->next;
     }
     return new_list;
@@ -733,7 +760,8 @@
                 stats_event (release->localmount, NULL, NULL);
             continue;
         }
-        relay_free (release);
+        if (release->cleanup == 0)
+            relay_free (release);
     }
 
     relay = to_start;
@@ -850,6 +878,7 @@
             if (master->bind)
                 m->bind = (char *)xmlStrdup (XMLSTR(master->bind));
             m->mount = (char *)xmlStrdup (XMLSTR(buf));
+            m->timeout = 4;
             r->masters = m;
             if (strncmp (buf, "/admin/streams?mount=/", 22) == 0)
                 r->localmount = (char *)xmlStrdup (XMLSTR(buf+21));
@@ -1221,6 +1250,7 @@
 {
     relay_server *relay = client->shared_data;
     source_t *source = relay->source;
+    int ret = -1;
 
     thread_mutex_lock (&source->lock);
     if (source_running (source))
@@ -1232,8 +1262,7 @@
         source_read (source);
         return 0;
     }
-    DEBUG2 ("counts are %d and %d", source->termination_count, source->listeners);
-    if (relay->running)
+    if (relay->running && relay->enable)
     {
         client_t *listener;
 
@@ -1244,20 +1273,18 @@
         listener = source->client_list;
         while (listener)
         {
-            client_set_queue (listener, NULL);
+            source_listener_detach (listener);
             listener = listener->next;
         }
+
         client->ops = &relay_startup_ops;
-        relay->running = 0;
         global_reduce_bitrate_sampling (global.out_bitrate);
         connection_close (&client->connection);
         if (client->parser)
             httpp_destroy (client->parser);
         client->parser = NULL;
-        source_clear_source (source);
         thread_mutex_unlock (&source->lock);
         thread_rwlock_unlock (&global.shutdown_lock);
-        slave_update_all_mounts();
         return 0;
     }
     if ((source->flags & SOURCE_TERMINATING) == 0)
@@ -1267,16 +1294,26 @@
     }
     if (source->termination_count)
     {
+        client->schedule_ms = client->worker->time_ms + 150;
+        DEBUG2 ("counts are %d and %d", source->termination_count, source->listeners);
         thread_mutex_unlock (&source->lock);
         return 0;
     }
     INFO1 ("shutting down relay %s", relay->localmount);
+    if (relay->enable == 0)
+    {
+        source_clear_source (source);
+        source_clear_listeners (source);
+        relay->running = 0;
+        client->ops = &relay_startup_ops;
+        ret = 0;
+    }
     thread_mutex_unlock (&source->lock);
     stats_event (relay->localmount, NULL, NULL);
     global_reduce_bitrate_sampling (global.out_bitrate);
     thread_rwlock_unlock (&global.shutdown_lock);
     slave_update_all_mounts();
-    return -1;
+    return ret;
 }
 
 

Modified: icecast/branches/kh/icecast/src/source.c
===================================================================
--- icecast/branches/kh/icecast/src/source.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/source.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -138,6 +138,7 @@
         /* make duplicates for strings or similar */
         src->mount = strdup (mount);
         src->listener_send_trigger = 10000;
+        src->format = calloc (1, sizeof(format_plugin_t));
 
         thread_mutex_create (&src->lock);
 
@@ -250,15 +251,12 @@
         client->shared_data = NULL;
         client_set_queue (client, NULL);
         /* do not count listeners who have joined but haven't done any processing */
-        if (client->respcode == 200)
-            i++;
+        i++;
         auth_release_listener (client, source->mount, mountinfo);
     }
     config_release_config ();
     if (i)
-    {
         stats_event_sub (NULL, "listeners", i);
-    }
     source->listeners = 0;
     source->prev_listeners = 0;
 }
@@ -278,8 +276,7 @@
         source->dumpfile = NULL;
     }
 
-    format_free_plugin (source->format);
-    source->format = NULL;
+    format_plugin_clear (source->format);
 
     /* flush out the stream data, we don't want any left over */
 
@@ -346,6 +343,7 @@
     thread_mutex_destroy (&source->lock);
 
     INFO1 ("freeing source \"%s\"", source->mount);
+    free (source->format);
     free (source->mount);
     free (source);
     return 1;
@@ -388,7 +386,7 @@
 
     source->format->sent_bytes += kbytes_sent*1024;
     stats_event_args (source->mount, "outgoing_kbitrate", "%ld",
-            (8 * rate_avg (source->format->out_bitrate))/1000);
+            (8 * rate_avg (source->format->out_bitrate))/1024);
     stats_event_args (source->mount, "incoming_bitrate", "%ld", incoming_rate);
     stats_event_args (source->mount, "total_bytes_read",
             "%"PRIu64, source->format->read_bytes);
@@ -445,7 +443,7 @@
                 stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
             }
         }
-        if (source->client && current >= source->client_stats_update)
+        if (current >= source->client_stats_update)
         {
             source_change_worker (source);
             update_source_stats (source);
@@ -481,13 +479,13 @@
                         source->timeout, (long)current);
                 WARN0 ("Disconnecting source due to socket timeout");
                 source->flags &= ~SOURCE_RUNNING;
+                skip = 0;
                 break;
             }
-            rate_add (source->format->in_bitrate, 0, current);
-            if (source->skip_duration < 60)
-                source->skip_duration = 80;
+            if (source->skip_duration < 20)
+                source->skip_duration = 30;
             else
-                source->skip_duration = (long)(source->skip_duration *1.8);
+                source->skip_duration = (long)(source->skip_duration * 1.8);
             break;
         }
         source->skip_duration = (long)(source->skip_duration * 0.9);
@@ -580,6 +578,12 @@
     source_t *source = client->shared_data;
 
     thread_mutex_lock (&source->lock);
+    if (client->connection.discon_time &&
+            client->connection.discon_time <= client->worker->current_time.tv_sec)
+    {
+        source->flags &= ~SOURCE_RUNNING;
+        INFO1 ("streaming duration expired on %s", source->mount);
+    }
     if (source_running (source))
         source_read (source);
     else
@@ -726,7 +730,7 @@
 
     if (client->respcode == 0)
     {
-        int (*build_headers)(source_t *, client_t *) = format_general_headers;
+        int (*build_headers)(format_plugin_t *, client_t *) = format_general_headers;
 
         if (source_running (source) == 0)
         {
@@ -737,13 +741,11 @@
             build_headers = source->format->create_client_data;
 
         refbuf->len = 0;
-        if (build_headers (source, client) < 0)
+        if (build_headers (source->format, client) < 0)
         {
             ERROR0 ("internal problem, dropping client");
             return -1;
         }
-        stats_event_inc (NULL, "listeners");
-        stats_event_inc (NULL, "listener_connections");
         stats_event_inc (source->mount, "listener_connections");
     }
     if (client->pos == refbuf->len)
@@ -766,6 +768,15 @@
 }
 
 
+void source_listener_detach (client_t *client)
+{
+    source_t *source = client->shared_data;
+    if (client->check_buffer != http_source_listener && 
+            (client->flags & CLIENT_HAS_INTRO_CONTENT) == 0)
+        client_set_queue (client, NULL);
+    client->check_buffer = source->format->write_buf_to_client;
+}
+
 /* general send routine per listener.
  */
 static int send_to_listener (client_t *client)
@@ -780,27 +791,25 @@
         return -1;
     if (source->fallback.mount)
     {
+        int move_failed;
+        client_t **pnext;
         thread_mutex_lock (&source->lock);
-
-        if (client->flags & CLIENT_IS_SLAVE)
-            client->schedule_ms = client->worker->time_ms + 100;
-        else
+        // remove from the sources client list
+        pnext = &source->client_list;
+        while (*pnext && *pnext != client)
+            pnext = &((*pnext)->next);
+        *pnext = client->next;
+        source->listeners--;
+        source_listener_detach (client);
+        thread_mutex_unlock (&source->lock);
+        move_failed = move_listener (client, &source->fallback);
+        thread_mutex_lock (&source->lock);
+        if (move_failed)
         {
-            // remove from the sources client list
-            client_t **pnext = &source->client_list;
-            while (*pnext && *pnext != client)
-                pnext = &((*pnext)->next);
-            *pnext = client->next;
-            if (client->check_buffer != http_source_listener)
-            {
-                if ((client->flags & CLIENT_HAS_INTRO_CONTENT) == 0)
-                    client_set_queue (client, NULL);
-                client->check_buffer = source->format->write_buf_to_client;
-            }
-            thread_mutex_unlock (&source->lock);
-            move_listener (client, &source->fallback);
-            thread_mutex_lock (&source->lock);
-            source->listeners--;
+            client->next = source->client_list;
+            source->client_list = client;
+            source->listeners++;
+            client->schedule_ms = client->worker->time_ms + 50;
         }
         source->termination_count--;
         thread_mutex_unlock (&source->lock);
@@ -809,10 +818,10 @@
     if (source->flags & SOURCE_TERMINATING)
     {
         thread_mutex_lock (&source->lock);
-        DEBUG1 ("termination_count now %d",  source->termination_count);
+        source->termination_count--;
+        DEBUG2 ("termination count on %s now %d", source->mount, source->termination_count);
         client_set_queue (client, NULL);
         client->ops = &listener_pause_ops;
-        source->termination_count--;
         thread_mutex_unlock (&source->lock);
         return -1;
     }
@@ -831,6 +840,9 @@
 
     thread_mutex_lock (&source->lock);
 
+    if (client->refbuf == NULL)
+        client->check_buffer = source_queue_advance;
+
     // do we migrate this listener to the same handler as the source client
     if (source->client && source->client->worker != client->worker)
         listener_change_worker (client, source);
@@ -861,12 +873,9 @@
     }
     if (loop == 0)
         client->schedule_ms -= 500;
-    if (total_written)
-    {
-        rate_add (source->format->out_bitrate, total_written, client->worker->time_ms);
-        global_add_bitrates (global.out_bitrate, total_written, client->worker->time_ms);
-        source->bytes_sent_since_update += total_written;
-    }
+    rate_add (source->format->out_bitrate, total_written, client->worker->time_ms);
+    global_add_bitrates (global.out_bitrate, total_written, client->worker->time_ms);
+    source->bytes_sent_since_update += total_written;
 
     /* the refbuf referenced at head (last in queue) may be marked for deletion
      * if so, check to see if this client is still referring to it */
@@ -932,8 +941,8 @@
             stats_event (source->mount, "audio_info", str);
         }
     }
-    source->format->in_bitrate = rate_setup (50, 1);
-    source->format->out_bitrate = rate_setup (50, 1000);
+    source->format->in_bitrate = rate_setup (60, 1);
+    source->format->out_bitrate = rate_setup (9000, 1000);
 
     thread_mutex_unlock (&source->lock);
 
@@ -993,13 +1002,15 @@
 
 void source_set_fallback (source_t *source, const char *dest_mount)
 {
+    source->termination_count = source->listeners;
     if (dest_mount == NULL)
         return;
 
     source->fallback.flags = FS_FALLBACK;
     source->fallback.mount = strdup (dest_mount);
     source->fallback.limit = (int)(rate_avg (source->format->in_bitrate) * 1.02);
-    source->termination_count = source->listeners;
+    INFO4 ("fallback set on %s to %s(%d) with %d listeners", source->mount, dest_mount,
+            source->fallback.limit, source->listeners);
 }
 
 void source_shutdown (source_t *source, int with_fallback)
@@ -1016,7 +1027,7 @@
             source_run_script (mountinfo->on_disconnect, source->mount);
         auth_stream_end (mountinfo, source->mount);
 
-        if (with_fallback)
+        if (with_fallback && global.running == ICE_RUNNING)
             source_set_fallback (source, mountinfo->fallback_mount);
     }
     config_release_config();
@@ -1582,7 +1593,7 @@
     *pnext = client->next;
     value = --source->listeners;
     if (source->listeners == 0)
-        rate_reduce (source->format->out_bitrate, 0);
+        rate_reduce (source->format->out_bitrate, 1000);
 
     stats_event_dec (NULL, "listeners");
     stats_event_args (source->mount, "listeners", "%lu", value);
@@ -1599,7 +1610,7 @@
 
 int source_add_listener (const char *mount, mount_proxy *mountinfo, client_t *client)
 {
-    int loop = 10;
+    int loop = 10, bitrate = 0;
     int within_limits;
     source_t *source;
     mount_proxy *minfo = mountinfo;
@@ -1626,8 +1637,27 @@
                     break;
                 thread_mutex_unlock (&source->lock);
             }
+            if (minfo && minfo->limit_rate)
+                bitrate = minfo->limit_rate;
             if (minfo == NULL || minfo->fallback_mount == NULL)
+            {
+                if (bitrate)
+                {
+                    fbinfo f;
+                    f.flags = FS_FALLBACK;
+                    f.mount = (char *)mount;
+                    f.fallback = NULL;
+                    f.limit = bitrate/8;
+                    if (move_listener (client, &f) == 0)
+                    {
+                        /* source dead but fallback to file found */
+                        stats_event_inc (NULL, "listeners");
+                        stats_event_inc (NULL, "listener_connections");
+                        return 0;
+                    }
+                }
                 return -2;
+            }
             mount = minfo->fallback_mount;
             minfo = config_find_mount (config_get_config_unlocked(), mount);
             loop--;
@@ -1721,6 +1751,9 @@
     client->refbuf->len = PER_CLIENT_REFBUF_SIZE;
     memset (client->refbuf->data, 0, PER_CLIENT_REFBUF_SIZE);
 
+    stats_event_inc (NULL, "listeners");
+    stats_event_inc (NULL, "listener_connections");
+
     source_setup_listener (source, client);
     client->flags |= CLIENT_ACTIVE;
     thread_mutex_unlock (&source->lock);

Modified: icecast/branches/kh/icecast/src/source.h
===================================================================
--- icecast/branches/kh/icecast/src/source.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/source.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -102,6 +102,7 @@
 void source_free_source(source_t *source);
 void source_move_clients (source_t *source, source_t *dest);
 int source_remove_client(void *key);
+void source_listener_detach (client_t *client);
 void source_main(source_t *source);
 void source_recheck_mounts (int update_all);
 int  source_add_listener (const char *mount, mount_proxy *mountinfo, client_t *client);

Modified: icecast/branches/kh/icecast/src/stats.c
===================================================================
--- icecast/branches/kh/icecast/src/stats.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/stats.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -585,7 +585,7 @@
     int ret = 0;
     event_listener_t *listener = client->shared_data;
 
-    if (client->connection.error)
+    if (client->connection.error || global.running != ICE_RUNNING)
         return -1;
     if (client->flags & STATS_LARGE)
         loop = 4;
@@ -1087,10 +1087,14 @@
 
         if (source == NULL)
         {
-            /* no source_t is reserved so remove them now */
-            snode = avl_get_next (snode);
-            avl_delete (_stats.source_tree, src, _free_source_stats);
-            continue;
+            stats_node_t *node = _find_node (src->stats_tree, "file");
+            if (node == NULL)
+            {
+                /* no source_t and no fallbakc file stat, so delete */
+                snode = avl_get_next (snode);
+                avl_delete (_stats.source_tree, src, _free_source_stats);
+                continue;
+            }
         }
 
         snode = avl_get_next (snode);
@@ -1110,7 +1114,7 @@
 
     thread_mutex_lock (&_stats_mutex);
     snprintf (buffer, sizeof(buffer), "%" PRIu64,
-            (int64_t)global_getrate_avg (global.out_bitrate) * 8 / 1000);
+            (int64_t)global_getrate_avg (global.out_bitrate) * 8 / 1024);
     process_event_unlocked (&event);
     /* retrieve the list of closing down clients */
     listener = _stats.listeners_removed;

Modified: icecast/branches/kh/icecast/src/util.c
===================================================================
--- icecast/branches/kh/icecast/src/util.c	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/util.c	2009-09-29 01:44:20 UTC (rev 16593)
@@ -713,27 +713,45 @@
     return calc;
 }
 
+static void rate_purge_entries (struct rate_calc *calc, uint64_t cutoff)
+{
+    struct rate_calc_node *node = calc->current->next;
+    int count = calc->blocks;
 
+    while (count && node->index <= cutoff)
+    {
+        struct rate_calc_node *to_go = node;
+        node = calc->current->next = node->next;
+        calc->total -= to_go->value;
+        free (to_go);
+        count--;
+    }
+    calc->blocks = count;
+}
+
 /* add a value to sampled data, t is used to determine which sample
  * block the sample goes into.
  */
 void rate_add (struct rate_calc *calc, long value, uint64_t sid) 
 {
+    uint64_t cutoff = sid - calc->samples;
+
+    if (value == 0 && calc->current && calc->current->value == 0)
+    {
+        calc->current->index = sid; /* update the timestamp if 0 already present */
+        rate_purge_entries (calc, cutoff);
+        return;
+    }
     calc->total += value;
     if (calc->current == NULL || sid != calc->current->index)
     {
-        if (calc->blocks == calc->samples)
+        struct rate_calc_node *node = calc->current ? calc->current->next : NULL;
+        if (node == NULL || node->index > cutoff)
         {
-            calc->current = calc->current->next;
-            calc->total -= calc->current->value;
-            calc->current->value = value;
-            calc->current->index = sid;
-            return;
-        }
-        else
-        {
-            struct rate_calc_node *node = calloc (1, sizeof (*node));
+            node = calloc (1, sizeof (*node));
+
             node->index = sid;
+            node->value = value;
             calc->blocks++;
             if (calc->current)
             {
@@ -741,11 +759,18 @@
                 calc->current->next = node;
             }
             else
-            {
                 node->next = node;
-            }
             calc->current = node;
         }
+        else
+        {
+            calc->total -= node->value;
+            node->index = sid;
+            node->value = value;
+            calc->current = node;
+        }
+        rate_purge_entries (calc, cutoff);
+        return;
     }
     calc->current->value += value;
 }
@@ -759,29 +784,18 @@
 
     if (calc == NULL || calc->blocks < 2)
         return 0;
-    range = (calc->current->index - calc->current->next->index);
+    range = (calc->current->index - calc->current->next->index) + 1;
     if (range < 1)
         range = 1;
     return (long)(calc->total / range * calc->ssec);
 }
 
 /* reduce the samples used to calculate average */
-void rate_reduce (struct rate_calc *calc, unsigned int count)
+void rate_reduce (struct rate_calc *calc, unsigned int range)
 {
-    if (calc && count < calc->blocks)
+    if (calc && range && calc->blocks > 1)
     {
-        struct rate_calc_node *list = calc->current->next;
-        for (; calc->blocks > count; calc->blocks--)
-        {
-            struct rate_calc_node *to_go = list;
-            list = to_go->next;
-            calc->total -= to_go->value;
-            free (to_go);
-        }
-        if (calc->blocks)
-            calc->current->next = list;
-        else
-            calc->current = NULL;
+        rate_purge_entries (calc, calc->current->index - range);
     }
 }
 

Modified: icecast/branches/kh/icecast/src/util.h
===================================================================
--- icecast/branches/kh/icecast/src/util.h	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/src/util.h	2009-09-29 01:44:20 UTC (rev 16593)
@@ -61,7 +61,7 @@
 void rate_add (struct rate_calc *calc, long value, uint64_t t);
 long rate_avg (struct rate_calc *calc);
 void rate_free (struct rate_calc *calc);
-void rate_reduce (struct rate_calc *calc, unsigned int count);
+void rate_reduce (struct rate_calc *calc, unsigned int range);
 
 int get_line(FILE *file, char *buf, size_t siz);
 

Modified: icecast/branches/kh/icecast/win32/Icecast2win.clw
===================================================================
--- icecast/branches/kh/icecast/win32/Icecast2win.clw	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/win32/Icecast2win.clw	2009-09-29 01:44:20 UTC (rev 16593)
@@ -26,14 +26,14 @@
 Resource8=IDR_MENU3
 Resource9=IDD_ABOUTBOX
 Resource10=IDR_MENU4
-Resource11=IDD_SSTATUS (English (U.S.))
-Resource12=IDD_CONFIGDIALOG (English (U.S.))
-Resource13=IDD_STATSDIALOG (English (U.S.))
-Resource14=IDR_MENU2 (English (U.S.))
-Resource15=IDR_MENU3 (English (U.S.))
-Resource16=IDR_TRAY (English (U.S.))
-Resource17=IDD_ABOUTBOX (English (U.S.))
-Resource18=IDD_ICECAST2WIN_DIALOG (English (U.S.))
+Resource11=IDR_TRAY (English (U.S.))
+Resource12=IDD_ABOUTBOX (English (U.S.))
+Resource13=IDD_ICECAST2WIN_DIALOG (English (U.S.))
+Resource14=IDD_SSTATUS (English (U.S.))
+Resource15=IDD_CONFIGDIALOG (English (U.S.))
+Resource16=IDD_STATSDIALOG (English (U.S.))
+Resource17=IDR_MENU2 (English (U.S.))
+Resource18=IDR_MENU3 (English (U.S.))
 Resource19=IDR_MENU4 (English (U.S.))
 
 [CLS:CIcecast2winApp]

Modified: icecast/branches/kh/icecast/win32/Icecast2win.dsp
===================================================================
--- icecast/branches/kh/icecast/win32/Icecast2win.dsp	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/win32/Icecast2win.dsp	2009-09-29 01:44:20 UTC (rev 16593)
@@ -79,8 +79,8 @@
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 libspeex.lib theora_static_d.lib ogg.lib vorbis_static.lib pthreadVSE.lib ssleay32MT.lib libcurl.lib libxml2.lib libxslt.lib iconv.lib ws2_32.lib winmm.lib /nologo /version:2.3 /subsystem:windows /incremental:no /debug /machine:I386 /nodefaultlib:"libcd.lib libcmt.lib" /pdbtype:sept
-# SUBTRACT LINK32 /verbose
+# ADD LINK32 libspeex.lib theora_static_d.lib ogg.lib vorbis_static.lib pthreadVSE.lib ssleay32MT.lib libcurl.lib libxml2.lib libxslt.lib iconv.lib ws2_32.lib winmm.lib /nologo /version:2.3 /subsystem:windows /debug /machine:I386 /nodefaultlib:"libcd.lib libcmt.lib" /pdbtype:sept
+# SUBTRACT LINK32 /verbose /incremental:no /force
 
 !ENDIF 
 

Modified: icecast/branches/kh/icecast/win32/Icecast2winDlg.cpp
===================================================================
--- icecast/branches/kh/icecast/win32/Icecast2winDlg.cpp	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/win32/Icecast2winDlg.cpp	2009-09-29 01:44:20 UTC (rev 16593)
@@ -13,12 +13,12 @@
 #include <curl/curl.h>
 
 extern "C" {
-#include "thread.h"
-#include "avl.h"
-#include "log.h"
+#include "thread/thread.h"
+#include "avl/avl.h"
+#include "log/log.h"
 #include "global.h"
-#include "httpp.h"
-#include "sock.h"
+#include "httpp/httpp.h"
+#include "net/sock.h"
 #include "connection.h"
 #include "refbuf.h"
 #include "client.h"

Modified: icecast/branches/kh/icecast/win32/icecast.dsp
===================================================================
--- icecast/branches/kh/icecast/win32/icecast.dsp	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/win32/icecast.dsp	2009-09-29 01:44:20 UTC (rev 16593)
@@ -86,22 +86,57 @@
 # Begin Source File
 
 SOURCE=..\src\admin.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\auth.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\auth_htpasswd.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\auth_url.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\avl\avl.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
@@ -119,14 +154,35 @@
 # Begin Source File
 
 SOURCE=..\src\client.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\connection.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\event.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
@@ -144,114 +200,310 @@
 # Begin Source File
 
 SOURCE=..\src\format.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_flac.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_kate.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_midi.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_mp3.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_ogg.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_skeleton.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_speex.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_theora.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\format_vorbis.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\fserve.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\global.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\httpp\httpp.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\log\log.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\logging.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\md5.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\refbuf.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\net\resolver.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\sighandler.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\slave.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\net\sock.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\source.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\stats.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\thread\thread.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\timing\timing.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\util.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\xslt.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\yp.c
+
+!IF  "$(CFG)" == "icecast - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "icecast - Win32 Debug"
+
+!ENDIF 
+
 # End Source File
 # End Group
 # Begin Group "Header Files"

Modified: icecast/branches/kh/icecast/win32/icecast2.iss
===================================================================
--- icecast/branches/kh/icecast/win32/icecast2.iss	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/win32/icecast2.iss	2009-09-29 01:44:20 UTC (rev 16593)
@@ -3,7 +3,7 @@
 
 [Setup]
 AppName=Icecast2-KH
-AppVerName=Icecast v2.3.2-kh12
+AppVerName=Icecast v2.3.2-kh16
 AppPublisherURL=http://www.icecast.org
 AppSupportURL=http://www.icecast.org
 AppUpdatesURL=http://www.icecast.org
@@ -13,10 +13,10 @@
 LicenseFile=..\COPYING
 InfoAfterFile=..\README
 OutputDir=.
-OutputBaseFilename=icecast2_win32_v2.3.2-kh12_setup
+OutputBaseFilename=icecast2_win32_v2.3.2-kh16_setup
 WizardImageFile=icecast2logo2.bmp
 WizardImageStretch=no
-VersionInfoProductVersion=kh12
+VersionInfoProductVersion=kh16
 VersionInfoVersion=2.3.2
 ; uncomment the following line if you want your installation to run on NT 3.51 too.
 ; MinVersion=4,3.51

Modified: icecast/branches/kh/icecast/win32/icecastService.cpp
===================================================================
--- icecast/branches/kh/icecast/win32/icecastService.cpp	2009-09-28 16:54:28 UTC (rev 16592)
+++ icecast/branches/kh/icecast/win32/icecastService.cpp	2009-09-29 01:44:20 UTC (rev 16593)
@@ -33,10 +33,10 @@
 void installService (const char *path)
 {
 	if (path) {
-        TCHAR buffer [MAX_PATH] = "\"";
-        int len = GetModuleFileName (NULL, buffer+1, sizeof (buffer)-1);
+        TCHAR fullPath [MAX_PATH] = "\"";
+        int len = GetModuleFileName (NULL, fullPath+1, sizeof (fullPath)-1);
 
-		_snprintf (buffer+len+1, sizeof (buffer)-len, "\" \"%s\"", path);
+		_snprintf (fullPath+len+1, sizeof (fullPath)-len, "\" \"%s\"", path);
 
 		SC_HANDLE manager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
 		if (manager == NULL)
@@ -53,7 +53,7 @@
 			SERVICE_WIN32_OWN_PROCESS,
 			SERVICE_AUTO_START,
 			SERVICE_ERROR_IGNORE,
-			buffer,
+			fullPath,
 			NULL,
 			NULL,
 			NULL,
@@ -115,8 +115,6 @@
 void ServiceMain(int argc, char** argv) 
 { 
     ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
-    ServiceStatus.dwCurrentState = SERVICE_START_PENDING; 
-    ServiceStatus.dwControlsAccepted = 0;
     ServiceStatus.dwWin32ExitCode = 0; 
     ServiceStatus.dwServiceSpecificExitCode = 0; 
     ServiceStatus.dwCheckPoint = 0;



More information about the commits mailing list