[xiph-commits] r14653 - in icecast/branches/kh/icecast: . src web

karl at svn.xiph.org karl at svn.xiph.org
Thu Apr 3 08:15:11 PDT 2008


Author: karl
Date: 2008-04-03 08:15:10 -0700 (Thu, 03 Apr 2008)
New Revision: 14653

Modified:
   icecast/branches/kh/icecast/NEWS
   icecast/branches/kh/icecast/configure.in
   icecast/branches/kh/icecast/src/admin.c
   icecast/branches/kh/icecast/src/admin.h
   icecast/branches/kh/icecast/src/auth.c
   icecast/branches/kh/icecast/src/auth_htpasswd.c
   icecast/branches/kh/icecast/src/auth_url.c
   icecast/branches/kh/icecast/src/cfgfile.c
   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/global.h
   icecast/branches/kh/icecast/src/slave.c
   icecast/branches/kh/icecast/src/slave.h
   icecast/branches/kh/icecast/src/source.c
   icecast/branches/kh/icecast/src/stats.c
   icecast/branches/kh/icecast/src/stats.h
   icecast/branches/kh/icecast/web/status2.xsl
Log:
sync work to kh33


Modified: icecast/branches/kh/icecast/NEWS
===================================================================
--- icecast/branches/kh/icecast/NEWS	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/NEWS	2008-04-03 15:15:10 UTC (rev 14653)
@@ -15,6 +15,26 @@
 any extra tags are show in the conf/icecast.xml.dist file
 
 
+2.3-kh33
+. master/slave update.
+  slave mode only issues a streamlist.txt request if the /admin/slaves request
+  fails.  /admin/slaves also acts as an mountpoint for the slave relays by
+  passing a mount= arg and auth.
+  You can now define a <mount> for /admin/slaves to define how slave
+  authentication is done eg url (listener_add) or htpasswd.
+  Once authenticated, the slave can bypass any limits like max listeners etc.
+  The slave also allows for defining a <master> tag block instead of <master-*>
+  tags allowed are <username> <password> <server> <port> <redirect> <bind>
+  auth url can take an "icecast-slave: 1" header, which makes client act as a
+  slave and bypass mount limits.
+. build fixups for OpenBSD and cases where IPV6_V6ONLY is missing
+. move 'clients' limit check to after admin request check, means admin commands
+  can work even if the limit is reached. removes a lock taken as well.
+. drop connections to known slave relays if we find that the destination source
+  is a fallback to file, as this would cause high bandwidth usage.
+. stats fix for inactive on-demand relay stats without a mount definition.
+. added some minor consistency checks.
+
 2.3-kh32
 . crash fix for a failing on-demand relay.
 . incorrect logfile settings for timestamp setting, for playlist and access.log

Modified: icecast/branches/kh/icecast/configure.in
===================================================================
--- icecast/branches/kh/icecast/configure.in	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/configure.in	2008-04-03 15:15:10 UTC (rev 14653)
@@ -1,4 +1,4 @@
-AC_INIT([Icecast], [2.3-kh32], [karl at xiph.org])
+AC_INIT([Icecast], [2.3-kh33], [karl at xiph.org])
 
 AC_PREREQ(2.59)
 AC_CONFIG_SRCDIR(src/main.c)

Modified: icecast/branches/kh/icecast/src/admin.c
===================================================================
--- icecast/branches/kh/icecast/src/admin.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/admin.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -52,7 +52,6 @@
         int response);
 static void command_stats(client_t *client, const char *filename);
 static void command_stats_mount (client_t *client, source_t *source, int response);
-static void command_list_mounts(client_t *client, int response);
 static void command_kill_client(client_t *client, source_t *source,
         int response);
 static void command_manageauth(client_t *client, source_t *source,
@@ -333,6 +332,19 @@
     if (connection_check_admin_pass (client->parser))
         client->authenticated = 1;
 
+    /* special case for slaves requesting a streamlist for authenticated relaying */
+    if (strcmp (uri, "streams") == 0)
+    {
+        client->is_slave = 1;
+        auth_add_listener ("/admin/streams", client);
+        return 0;
+    }
+    if (strcmp (uri, "streamlist.txt") == 0)
+    {
+        if (connection_check_relay_pass (client->parser))
+            client->authenticated = 1;
+    }
+
     if (mount)
     {
         /* no auth/stream required for this */
@@ -362,13 +374,6 @@
         return 0;
     }
 
-    /* no auth/stream required for this */
-    if (strcmp (uri, "streamlist.txt") == 0)
-    {
-        if (connection_check_relay_pass (client->parser))
-            client->authenticated = 1;
-    }
-
     admin_handle_general_request (client, uri);
     return 0;
 }
@@ -1090,7 +1095,7 @@
 }
 
 
-static void command_list_mounts(client_t *client, int response)
+void command_list_mounts(client_t *client, int response)
 {
     DEBUG0("List mounts request");
 
@@ -1099,6 +1104,7 @@
         char *buf;
         int remaining = PER_CLIENT_REFBUF_SIZE;
         int ret;
+
         redirector_update (client);
 
         buf = client->refbuf->data;
@@ -1106,7 +1112,10 @@
                 "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
         client->respcode = 200;
 
-        stats_get_streamlist (buf+ret, remaining-ret);
+        if (strcmp (httpp_getvar (client->parser, HTTPP_VAR_URI), "/admin/streams") == 0)
+            client->refbuf->next = stats_get_streams ();
+        else
+            stats_get_streamlist (buf+ret, remaining-ret);
 
         client->refbuf->len = strlen (client->refbuf->data);
         fserve_add_client (client, NULL);

Modified: icecast/branches/kh/icecast/src/admin.h
===================================================================
--- icecast/branches/kh/icecast/src/admin.h	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/admin.h	2008-04-03 15:15:10 UTC (rev 14653)
@@ -26,6 +26,7 @@
     TEXT
 } admin_response_type;
 
+void command_list_mounts(client_t *client, int response);
 int  admin_handle_request (client_t *client, const char *uri);
 void admin_mount_request (client_t *client, const char *uri);
 void admin_source_listeners (source_t *source, xmlNodePtr node);

Modified: icecast/branches/kh/icecast/src/auth.c
===================================================================
--- icecast/branches/kh/icecast/src/auth.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/auth.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -382,7 +382,7 @@
 
 
 /* Add client to source if it finds one. If a 0 is returned then the client should not be
- * touched, if the return value is -1 then the it failed to add and should not be touched.
+ * touched, if the return value is -1 then it failed to add and should not be touched.
  * If it's a -2 value then the client is still around for any further processing.
  */
 static int add_listener_to_source (const char *mount, mount_proxy *mountinfo, client_t *client)
@@ -424,6 +424,11 @@
         /* ok, we found a source and it is locked */
         if (client->is_slave)
         {
+            if (source->client == NULL && source->on_demand == 0)
+            {
+                client_send_403 (client, "Slave relay reading from time unregulated stream");
+                return -1;
+            }
             INFO0 ("client is from a slave, bypassing limits");
             break;
         }
@@ -532,6 +537,22 @@
 {
     int ret = 0;
 
+    /* check whether we are processing a streamlist request for slaves */
+    if (strcmp (mount, "/admin/streams") == 0)
+    {
+        if (client->authenticated == 0)
+        {
+            client_send_401 (client, NULL);
+            return 0;
+        }
+        mount = httpp_get_query_param (client->parser, "mount");
+        if (mount == NULL)
+        {
+            command_list_mounts (client, TEXT);
+            return 0;
+        }
+        mountinfo = config_find_mount (config_get_config_unlocked(), mount);
+    }
     client->authenticated = 1;
 
     /* Here we are parsing the URI request to see if the extension is .xsl, if
@@ -630,9 +651,10 @@
     /* we don't need any more data from the listener, just setup for writing */
     client->refbuf->len = PER_CLIENT_REFBUF_SIZE;
 
-    if (connection_check_relay_pass(client->parser))
+    if (connection_check_relay_pass (client->parser))
     {
         client->is_slave = 1;
+        client->authenticated = 1;
         INFO0 ("client connected as slave");
     }
     config = config_get_config();
@@ -643,7 +665,7 @@
         client_send_403 (client, "mountpoint unavailable");
         return;
     }
-    if (mountinfo && mountinfo->auth && mountinfo->auth->authenticate)
+    if (client->authenticated == 0 && mountinfo && mountinfo->auth && mountinfo->auth->authenticate)
     {
         auth_client *auth_user;
 

Modified: icecast/branches/kh/icecast/src/auth_htpasswd.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_htpasswd.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/auth_htpasswd.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 
 #include "auth.h"
+#include "auth_htpasswd.h"
 #include "source.h"
 #include "client.h"
 #include "cfgfile.h"

Modified: icecast/branches/kh/icecast/src/auth_url.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_url.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/auth_url.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -30,6 +30,12 @@
  *
  * icecast-auth-timelimit: 900
  *
+ * A listening client may be a slave relay and as such you may want it to avoid
+ * certain checks like max listeners. Send this header back if to wish icecast
+ * to treat the client as a slave relay.
+ *
+ * icecast-slave: 1
+ *
  * On client disconnection another request can be sent to a URL with the POST
  * information of
  *
@@ -170,6 +176,9 @@
             sscanf ((char *)ptr+url->timelimit_header_len, "%u\r\n", &limit);
             client->con->discon_time = global.time + limit;
         }
+        if (strncasecmp (ptr, "icecast-slave: 1", 16) == 0)
+            client->is_slave =1;
+
         if (strncasecmp (ptr, "icecast-auth-message: ", 22) == 0)
         {
             char *eol;

Modified: icecast/branches/kh/icecast/src/cfgfile.c
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/cfgfile.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -869,12 +869,13 @@
         { "username",           config_get_str,     &config->master_username },
         { "password",           config_get_str,     &config->master_password },
         { "bind",               config_get_str,     &config->master_bind },
-        { "update-interval",    config_get_int,     &config->master_update_interval },
+        { "interval",           config_get_int,     &config->master_update_interval },
         { "relay-auth",         config_get_bool,    &config->master_relay_auth },
         { "redirect",           config_get_bool,    &config->master_redirect },
         { NULL, NULL, NULL },
     };
 
+    config->master_relay_auth = 1;
     if (parse_xml_tags (node, icecast_tags))
         return -1;
 

Modified: icecast/branches/kh/icecast/src/client.c
===================================================================
--- icecast/branches/kh/icecast/src/client.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/client.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -45,14 +45,11 @@
 #define CATMODULE "client"
 
 /* create a client_t with the provided connection and parser details. Return
- * 0 on success, -1 if server limit has been reached.  In either case a
- * client_t is returned just in case a message needs to be returned. Should
- * be called with global lock held.
+ * client_t ready for use.  Should be called with global lock held.
  */
-int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser)
+client_t *client_create (connection_t *con, http_parser_t *parser)
 {
     client_t *client = (client_t *)calloc(1, sizeof(client_t));
-    int ret = 0;
 
     if (client == NULL)
         abort();
@@ -71,20 +68,6 @@
             }
         }
     }
-
-    /* don't do client limit check if on an SSL socket, as that will be an admin request */
-    if (not_ssl_connection (con))
-    {
-        ice_config_t *config = config_get_config ();
-
-        if (config->client_limit < global.clients)
-        {
-            WARN2 ("server client limit reached (%d/%d)", config->client_limit, global.clients);
-            ret = -1;
-        }
-        config_release_config ();
-    }
-
     stats_event_args (NULL, "clients", "%d", global.clients);
     client->con = con;
     client->parser = parser;
@@ -92,8 +75,7 @@
     client->refbuf->len = 0; /* force reader code to ignore buffer contents */
     client->pos = 0;
     client->write_to_client = format_generic_write_to_client;
-    *c_ptr = client;
-    return ret;
+    return client;
 }
 
 

Modified: icecast/branches/kh/icecast/src/client.h
===================================================================
--- icecast/branches/kh/icecast/src/client.h	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/client.h	2008-04-03 15:15:10 UTC (rev 14653)
@@ -87,7 +87,7 @@
     struct _client_tag *next;
 };
 
-int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser);
+client_t *client_create (connection_t *con, http_parser_t *parser);
 void client_destroy(client_t *client);
 void client_send_504(client_t *client, char *message);
 void client_send_416(client_t *client);
@@ -97,8 +97,8 @@
 void client_send_403redirect (client_t *client, const char *mount, const char *reason);
 void client_send_400(client_t *client, char *message);
 void client_send_302(client_t *client, const char *location);
-int client_send_bytes (client_t *client, const void *buf, unsigned len);
-int client_read_bytes (client_t *client, void *buf, unsigned len);
+int  client_send_bytes (client_t *client, const void *buf, unsigned len);
+int  client_read_bytes (client_t *client, void *buf, unsigned len);
 void client_set_queue (client_t *client, refbuf_t *refbuf);
 
 #endif  /* __CLIENT_H__ */

Modified: icecast/branches/kh/icecast/src/connection.c
===================================================================
--- icecast/branches/kh/icecast/src/connection.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/connection.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -112,7 +112,9 @@
 #endif
 
 /* filtering client connection based on IP */
-cache_file_contents banned_ip, allowed_ip, useragents;
+cache_file_contents banned_ip, allowed_ip;
+/* filtering listener connection based on useragent */
+cache_file_contents useragents;
 
 int connection_running = 0;
 rwlock_t _source_shutdown_rwlock;
@@ -732,14 +734,7 @@
             client_t *client = NULL;
 
             global_lock();
-            if (client_create (&client, con, NULL) < 0)
-            {
-                global_unlock();
-                client_send_403 (client, "Icecast connection limit reached");
-                /* don't be too eager as this is an imposed hard limit */
-                thread_sleep (400000);
-                continue;
-            }
+            client = client_create (con, NULL);
             global_unlock();
 
             if (client->server_conn->ssl && ssl_ok)
@@ -778,8 +773,11 @@
 
 void connection_thread_startup ()
 {
-    if (conn_tid == NULL)
-        conn_tid = thread_create ("connection", connection_thread, NULL, THREAD_ATTACHED);
+    connection_running = 0;
+    while (conn_tid)
+        thread_sleep (100001);
+
+    conn_tid = thread_create ("connection", connection_thread, NULL, THREAD_ATTACHED);
 }
 
 void connection_thread_shutdown ()
@@ -1171,6 +1169,7 @@
     aliases *alias;
     ice_config_t *config;
     char *uri = passed_uri;
+    int client_limit_reached = 0;
 
     DEBUG1 ("start with %s", passed_uri);
     config = config_get_config();
@@ -1202,6 +1201,11 @@
         }
         alias = alias->next;
     }
+    if (global.clients > config->client_limit)
+    {
+        client_limit_reached = 1;
+        WARN2 ("server client limit reached (%d/%d)", config->client_limit, global.clients);
+    }
     config_release_config();
 
     stats_event_inc(NULL, "client_connections");
@@ -1212,7 +1216,11 @@
         if (uri != passed_uri) free (uri);
         return;
     }
-    auth_add_listener (uri, client);
+    /* drop non-admin GET requests here if clients limit reached */
+    if (client_limit_reached)
+        client_send_403 (client, "Too many clients connected");
+    else
+        auth_add_listener (uri, client);
     if (uri != passed_uri) free (uri);
 }
 

Modified: icecast/branches/kh/icecast/src/global.h
===================================================================
--- icecast/branches/kh/icecast/src/global.h	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/global.h	2008-04-03 15:15:10 UTC (rev 14653)
@@ -50,7 +50,6 @@
 
     /* redirection to slaves */
     unsigned int redirect_count;
-    struct _redirect_host *redirectors;
 
     spin_t spinlock;
     struct rate_calc *out_bitrate;

Modified: icecast/branches/kh/icecast/src/slave.c
===================================================================
--- icecast/branches/kh/icecast/src/slave.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/slave.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -62,6 +62,15 @@
 
 #define CATMODULE "slave"
 
+typedef struct _redirect_host
+{
+    struct _redirect_host *next;
+    time_t next_update;
+    char *server;
+    int port;
+} redirect_host;
+
+
 static void *_slave_thread(void *arg);
 static void redirector_add (const char *server, int port, int interval);
 static redirect_host *find_slave_host (const char *server, int port);
@@ -74,6 +83,8 @@
 static time_t streamlist_check = 0;
 static rwlock_t slaves_lock;
 
+redirect_host *redirectors;
+
 relay_server *relay_free (relay_server *relay)
 {
     relay_server *next = relay->next;
@@ -175,6 +186,7 @@
     update_settings = 0;
     update_all_mounts = 0;
     restart_connection_thread = 0;
+    redirectors = NULL;
 #ifndef HAVE_CURL
     ERROR0 ("streamlist request disabled, rebuild with libcurl if required");
 #endif
@@ -204,8 +216,8 @@
         return 0;
     }
     which=(int) (((float)global.redirect_count)*rand()/(RAND_MAX+1.0)) + 1;
-    checking = global.redirectors;
-    trail = &global.redirectors;
+    checking = redirectors;
+    trail = &redirectors;
 
     DEBUG2 ("random selection %d (out of %d)", which, global.redirect_count);
     while (checking)
@@ -231,7 +243,7 @@
             /* add enough for "http://" the port ':' and nul */
             int len = strlen (mountpoint) + strlen (checking->server) + 13;
 
-            INFO2 ("redirecting client to slave server "
+            INFO2 ("redirecting listener to slave server "
                     "at %s:%d", checking->server, checking->port);
             location = malloc (len);
             snprintf (location, len, "http://%s:%d%s", checking->server,
@@ -320,7 +332,7 @@
                 "\r\n",
                 mount,
                 server_id,
-                relay->mp3metadata?"Icy-MetaData: 1\r\n":"",
+                relay->mp3metadata ? "Icy-MetaData: 1\r\n" : "",
                 auth_header);
         memset (header, 0, sizeof(header));
         if (util_read_header (con->sock, header, 4096, READ_ENTIRE_HEADER) == 0)
@@ -377,15 +389,7 @@
                 break;
             }
             global_lock ();
-            if (client_create (&client, con, parser) < 0)
-            {
-                global_unlock ();
-                /* make sure only the client_destory frees these */
-                con = NULL;
-                parser = NULL;
-                client_destroy (client);
-                break;
-            }
+            client = client_create (con, parser);
             global_unlock ();
             sock_set_blocking (streamsock, SOCK_NONBLOCK);
             client_set_queue (client, NULL);
@@ -524,7 +528,10 @@
         {
             DEBUG1("Adding relay source at mountpoint \"%s\"", relay->localmount);
             if (relay->on_demand)
+            {
+                relay->start = global.time;
                 slave_update_all_mounts();
+            }
         }
         else
             WARN1 ("new relay but source \"%s\" already exists", relay->localmount);
@@ -548,18 +555,31 @@
 
             source->on_demand = relay->on_demand;
 
-            if (mountinfo && mountinfo->fallback_mount && mountinfo->fallback_override)
+            if (mountinfo)
             {
-                source_t *fallback;
-                avl_tree_rlock (global.source_tree);
-                fallback = source_find_mount (mountinfo->fallback_mount);
-                if (fallback && fallback->running && fallback->listeners)
+                if (mountinfo->fallback_mount && mountinfo->fallback_override)
                 {
-                   DEBUG1 ("fallback running with %lu listeners", fallback->listeners);
-                   source->on_demand_req = 1;
+                    source_t *fallback;
+                    avl_tree_rlock (global.source_tree);
+                    fallback = source_find_mount (mountinfo->fallback_mount);
+                    if (fallback && fallback->running && fallback->listeners)
+                    {
+                        DEBUG1 ("fallback running with %lu listeners", fallback->listeners);
+                        source->on_demand_req = 1;
+                    }
+                    avl_tree_unlock (global.source_tree);
                 }
-                avl_tree_unlock (global.source_tree);
             }
+            else
+            {
+                if (relay->start)
+                {
+                    thread_mutex_lock (&relay->source->lock);
+                    source_update_settings (config, relay->source, mountinfo);
+                    thread_mutex_unlock (&relay->source->lock);
+                    relay->start = 0;
+                }
+            }
             config_release_config();
             if (source->on_demand_req == 0)
                 break;
@@ -598,6 +618,7 @@
             thread_mutex_unlock (&relay->source->lock);
             config_release_config ();
             stats_event (relay->localmount, "listeners", "0");
+            relay->start = global.time;
         }
     }
 }
@@ -827,13 +848,17 @@
         {
             relay_server *r = calloc (1, sizeof (relay_server));
             relay_server_master *m = calloc (1, sizeof (relay_server_master));
+
             m->ip = (char *)xmlStrdup (XMLSTR(master->server));
             m->port = master->port;
             if (master->bind)
                 m->bind = (char *)xmlStrdup (XMLSTR(master->bind));
             m->mount = (char *)xmlStrdup (XMLSTR(buf));
             r->masters = m;
-            r->localmount = (char *)xmlStrdup (XMLSTR(buf));
+            if (strncmp (buf, "/admin/streams?mount=/", 22) == 0)
+                r->localmount = (char *)xmlStrdup (XMLSTR(buf+21));
+            else
+                r->localmount = (char *)xmlStrdup (XMLSTR(buf));
             r->mp3metadata = 1;
             r->on_demand = master->on_demand;
             r->interval = master->max_interval;
@@ -874,7 +899,7 @@
         port = master->ssl_port;
     }
     snprintf (auth, sizeof (auth), "%s:%s", master->username, master->password);
-    snprintf (url, sizeof (url), "%s://%s:%d/admin/streamlist.txt%s",
+    snprintf (url, sizeof (url), "%s://%s:%d/admin/streams%s",
             protocol, master->server, port, master->args);
     handle = curl_easy_init ();
     curl_easy_setopt (handle, CURLOPT_USERAGENT, master->server_id);
@@ -892,7 +917,14 @@
         curl_easy_setopt (handle, CURLOPT_INTERFACE, master->bind);
 
     if (curl_easy_perform (handle) != 0)
-        WARN2 ("Failed URL access \"%s\" (%s)", url, error);
+    {
+        /* fall back to traditional request */
+        snprintf (url, sizeof (url), "%s://%s:%d/admin/streamlist.txt%s",
+                protocol, master->server, port, master->args);
+        curl_easy_setopt (handle, CURLOPT_URL, url);
+        if (curl_easy_perform (handle) != 0)
+            WARN2 ("Failed URL access \"%s\" (%s)", url, error);
+    }
     if (master->ok)
     {
         /* process retrieved relays */
@@ -1094,10 +1126,10 @@
 static void redirector_clearall (void)
 {
     thread_rwlock_wlock (&slaves_lock);
-    while (global.redirectors)
+    while (redirectors)
     {
-        redirect_host *current = global.redirectors;
-        global.redirectors = current->next;
+        redirect_host *current = redirectors;
+        redirectors = current->next;
         INFO2 ("removing %s:%d", current->server, current->port);
         free (current->server);
         free (current);
@@ -1113,7 +1145,7 @@
     redirect_host *redirect;
     const char *rserver = httpp_get_query_param (client->parser, "rserver");
     const char *value;
-    int rport, interval;
+    int rport = 0, interval = 0;
 
     if (rserver==NULL) return;
     value = httpp_get_query_param (client->parser, "rport");
@@ -1125,7 +1157,6 @@
     interval = atoi (value);
     if (interval < 5) return;
 
-
     thread_rwlock_wlock (&slaves_lock);
     redirect = find_slave_host (rserver, rport);
     if (redirect == NULL)
@@ -1147,7 +1178,7 @@
  */
 static redirect_host *find_slave_host (const char *server, int port)
 {
-    redirect_host *redirect = global.redirectors;
+    redirect_host *redirect = redirectors;
     while (redirect)
     {
         if (strcmp (redirect->server, server) == 0 && redirect->port == port)
@@ -1180,8 +1211,8 @@
         redirect->next_update = (time_t)0;
     else
         redirect->next_update = global.time + interval;
-    redirect->next = global.redirectors;
-    global.redirectors = redirect;
+    redirect->next = redirectors;
+    redirectors = redirect;
     global.redirect_count++;
     INFO3 ("slave (%d) at %s:%d added", global.redirect_count,
             redirect->server, redirect->port);

Modified: icecast/branches/kh/icecast/src/slave.h
===================================================================
--- icecast/branches/kh/icecast/src/slave.h	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/slave.h	2008-04-03 15:15:10 UTC (rev 14653)
@@ -42,13 +42,6 @@
     struct _relay_server *next;
 } relay_server;
 
-typedef struct _redirect_host
-{
-    char *server;
-    int port;
-    time_t next_update;
-    struct _redirect_host *next;
-} redirect_host;
 
 void slave_initialize(void);
 void slave_shutdown(void);

Modified: icecast/branches/kh/icecast/src/source.c
===================================================================
--- icecast/branches/kh/icecast/src/source.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/source.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -359,6 +359,8 @@
 
     do
     {
+        client_t *leave_list = NULL;
+
         thread_mutex_lock (&source->lock);
 
         if (source->on_demand == 0 && source->format == NULL)
@@ -381,6 +383,13 @@
             client_t *client = source->active_clients;
             source->active_clients = client->next;
 
+            /* don't move known slave relays to streams which are not timed (fallback file) */
+            if (dest->client == NULL && client->is_slave)
+            {
+                client->next = leave_list;
+                leave_list = client;
+                continue;
+            }
             /* when switching a client to a different queue, be wary of the 
              * refbuf it's referring to, if it's http headers then we need
              * to write them so don't release it.
@@ -397,14 +406,12 @@
             dest->active_clients = client;
             count++;
         }
-        if (count != source->listeners)
-            WARN2 ("count %lu, listeners %lu", count, source->listeners);
-
+        source->active_clients = leave_list;
         INFO2 ("passing %lu listeners to \"%s\"", count, dest->mount);
 
         dest->listeners += count;
-        source->listeners = 0;
-        stats_event (source->mount, "listeners", "0");
+        source->listeners -= count;
+        stats_event_args (source->mount, "listeners", "%lu", source->listeners);
 
     } while (0);
 
@@ -700,6 +707,7 @@
 {
     client_t *client, **client_p;
     client_t *fast_clients = NULL, **fast_client_tail = &fast_clients;
+    unsigned long listener_count = 0;
 
     /* where do we start from */
     if (fast_clients_only)
@@ -731,6 +739,7 @@
             DEBUG0("Client removed");
             continue;
         }
+        listener_count++;
         if (fast_client && client->check_buffer != format_check_file_buffer)
         {
             client_t *to_move = client;
@@ -751,6 +760,10 @@
     if (fast_clients)
         *client_p = fast_clients;
 
+    /* consistency check, these should match */
+    if (fast_clients_only == 0 && listener_count != source->listeners)
+        ERROR3 ("mount %s has %lu, %lu", source->mount, listener_count, source->listeners);
+
     /* has the listener count changed */
     if (source->listeners != source->prev_listeners)
     {

Modified: icecast/branches/kh/icecast/src/stats.c
===================================================================
--- icecast/branches/kh/icecast/src/stats.c	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/stats.c	2008-04-03 15:15:10 UTC (rev 14653)
@@ -1118,7 +1118,7 @@
 
         if (source->hidden == 0)
         {
-            if (remaining <= strlen (source->source)+2)
+            if (remaining <= strlen (source->source)+3)
             {
                 WARN0 ("streamlist was truncated");
                 break;
@@ -1136,6 +1136,51 @@
     thread_mutex_unlock (&_stats_mutex);
 }
 
+
+
+/* get a list of refbufs which contain urls for slaves to use for relaying */
+refbuf_t *stats_get_streams (void)
+{
+    avl_node *node;
+    int remaining = 4096;
+    refbuf_t *start = refbuf_new (remaining), *cur = start;
+    const char *pre = "/admin/streams?mount=";
+    char *buffer = cur->data;
+
+    /* now the stats for each source */
+    thread_mutex_lock (&_stats_mutex);
+    node = avl_get_first(_stats.source_tree);
+    while (node)
+    {
+        int ret;
+        stats_source_t *source = (stats_source_t *)node->key;
+
+        if (source->hidden == 0)
+        {
+            if (remaining <= strlen (source->source) + strlen (pre) + 3)
+            {
+                cur->len = 4096 - remaining;
+                cur->next = refbuf_new (4096);
+                remaining = 4096;
+                cur = cur->next;
+                buffer = cur->data;
+            }
+            ret = snprintf (buffer, remaining, "%s%s\r\n", pre, source->source);
+            if (ret > 0)
+            {
+                buffer += ret;
+                remaining -= ret;
+            }
+        }
+        node = avl_get_next(node);
+    }
+    thread_mutex_unlock (&_stats_mutex);
+    cur->len = 4096 - remaining;
+    return start;
+}
+
+
+
 /* This removes any source stats from virtual mountpoints, ie mountpoints
  * where no source_t exists. This function requires the global sources lock
  * to be held before calling.

Modified: icecast/branches/kh/icecast/src/stats.h
===================================================================
--- icecast/branches/kh/icecast/src/stats.h	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/src/stats.h	2008-04-03 15:15:10 UTC (rev 14653)
@@ -77,6 +77,7 @@
 void stats_global(ice_config_t *config);
 stats_t *stats_get_stats(void);
 void stats_get_streamlist (char *buffer, size_t remaining);
+refbuf_t *stats_get_streams (void);
 void stats_clear_virtual_mounts (void);
 
 void stats_event(const char *source, const char *name, const char *value);

Modified: icecast/branches/kh/icecast/web/status2.xsl
===================================================================
--- icecast/branches/kh/icecast/web/status2.xsl	2008-04-02 22:38:58 UTC (rev 14652)
+++ icecast/branches/kh/icecast/web/status2.xsl	2008-04-03 15:15:10 UTC (rev 14653)
@@ -1,11 +1,11 @@
 <xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
-<xsl:output omit-xml-declaration="no" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
+<xsl:output method="text" media-type="text/plain" indent="yes" encoding="UTF-8" />
 <xsl:template match = "/icestats" >
 <pre>
-MountPoint,Connections,Stream Name,Current Listeners,Description,Currently Playing,Stream URL 
-Global,Client:<xsl:value-of select="connections" /> Source: <xsl:value-of select="source_connections" />,,<xsl:value-of select="listeners" />,,
+Global,Clients:<xsl:value-of select="connections" />,Sources:<xsl:value-of select="source_client_connections" />,,<xsl:value-of select="listeners" />,,
+MountPoint,Connections,Stream Name,Current Listeners,Description,Currently Playing,Stream URL
 <xsl:for-each select="source">
-<xsl:value-of select="@mount" />,,<xsl:value-of select="name" />,<xsl:value-of select="listeners" />,<xsl:value-of select="description" />,<xsl:value-of select="artist" /> - <xsl:value-of select="title" />,<xsl:value-of select="url" />
+<xsl:value-of select="@mount" />,<xsl:value-of select="listener_connections" />,<xsl:value-of select="server_name" />,<xsl:value-of select="listeners" />,<xsl:value-of select="server_description" />,<xsl:value-of select="artist" /> <xsl:value-of select="title" />,<xsl:value-of select="listenurl" />
 </xsl:for-each>
 </pre>
 </xsl:template>



More information about the commits mailing list