[xiph-commits] r17198 - in icecast/branches/kh/icecast: . src win32
karl at svn.xiph.org
karl at svn.xiph.org
Fri May 7 20:59:17 PDT 2010
Author: karl
Date: 2010-05-07 20:59:17 -0700 (Fri, 07 May 2010)
New Revision: 17198
Modified:
icecast/branches/kh/icecast/NEWS
icecast/branches/kh/icecast/config.h.vc6
icecast/branches/kh/icecast/configure.in
icecast/branches/kh/icecast/src/admin.c
icecast/branches/kh/icecast/src/auth.c
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/connection.c
icecast/branches/kh/icecast/src/connection.h
icecast/branches/kh/icecast/src/format_mp3.c
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/main.c
icecast/branches/kh/icecast/src/mpeg.c
icecast/branches/kh/icecast/src/mpeg.h
icecast/branches/kh/icecast/src/slave.c
icecast/branches/kh/icecast/src/source.c
icecast/branches/kh/icecast/src/stats.c
icecast/branches/kh/icecast/src/xslt.c
icecast/branches/kh/icecast/win32/icecast2.iss
Log:
kh23. mostly fixes. The new feature is the automatic banning of IPs if certain
mountpoints are accessed (useful for those /mount/index.html). The rest is
mainly pointer corruption fixes for relay updating/restarting/removal, stream
parsing for non-ogg streams and stats updating.
Modified: icecast/branches/kh/icecast/NEWS
===================================================================
--- icecast/branches/kh/icecast/NEWS 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/NEWS 2010-05-08 03:59:17 UTC (rev 17198)
@@ -16,6 +16,23 @@
any extra tags are show in the conf/icecast.xml.dist file
+2.3.2-kh23
+. if an inactive on-demand relay detects listeners on fallback then start relay
+ but do not move listeners until the connection is complete.
+. fix race condition with restarting non-ogg relays and stats being generated
+. make auth queue limit 150 before rejection.
+. A number of relay related fixes. these typically occur when a relay is either
+ restarted or was removed (eg disappeared from a master). There is also a
+ possible case of long held locking that is now gone.
+. add <ban-client>N</ban-client> mount option to add client IP to the internal
+ banned list for N seconds. subsequent attempts that have not timed out extend
+ the ban period. A stat count of banned entries is produced each second
+. reload from admin page was not restarting listen thread if signalfd used.
+. increase default queue block size on non-ogg streams to 2900
+. mpeg parsing fix for odd cases. This could appear as corrupt or stalled streams
+. fix listing of stats and listener details on fallback files
+. fix Location header reference from auth url
+
2.3.2-kh22
. Add mp3/aac sync marker alignment code. This makes the internal buffers contain
whole frames. allows for better transistion when moving listeners.
Modified: icecast/branches/kh/icecast/config.h.vc6
===================================================================
--- icecast/branches/kh/icecast/config.h.vc6 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/config.h.vc6 2010-05-08 03:59:17 UTC (rev 17198)
@@ -95,7 +95,7 @@
#define PACKAGE_NAME "Icecast"
/* Version number of package */
-#define VERSION "2.3.2-kh22"
+#define VERSION "2.3.2-kh23"
/* Define to the version of this package. */
#define PACKAGE_VERSION VERSION
Modified: icecast/branches/kh/icecast/configure.in
===================================================================
--- icecast/branches/kh/icecast/configure.in 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/configure.in 2010-05-08 03:59:17 UTC (rev 17198)
@@ -1,4 +1,4 @@
-AC_INIT([Icecast], [2.3.2-kh22], [karl at xiph.org])
+AC_INIT([Icecast], [2.3.2-kh23], [karl at xiph.org])
LT_INIT
AC_PREREQ(2.59)
Modified: icecast/branches/kh/icecast/src/admin.c
===================================================================
--- icecast/branches/kh/icecast/src/admin.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/admin.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -286,7 +286,7 @@
avl_tree_unlock(global.source_tree);
if (strncmp (cmd->request, "stats", 5) == 0)
{
- fserve_list_clients (client, mount, cmd->response, 0);
+ command_stats (client, uri);
return;
}
if (strncmp (cmd->request, "listclients", 11) == 0)
@@ -511,6 +511,10 @@
}
if (strcmp (function, "updatecfg") == 0)
{
+#ifdef HAVE_SIGNALFD
+ connection_running = 0;
+ connection_close_sigfd();
+#endif
global . schedule_config_reread = 1;
snprintf (buf, len, "Requesting reread of configuration file");
return 0;
Modified: icecast/branches/kh/icecast/src/auth.c
===================================================================
--- icecast/branches/kh/icecast/src/auth.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/auth.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -242,7 +242,7 @@
}
}
if (auth_postprocess_listener (auth_user) < 0)
- INFO0 ("listener connection failed");
+ DEBUG0 ("listener connection failed");
}
@@ -535,8 +535,10 @@
{
if (mountinfo->skip_accesslog)
client->flags |= CLIENT_SKIP_ACCESSLOG;
- if (mountinfo->no_mount)
+ if (mountinfo->ban_client || mountinfo->no_mount)
{
+ if (mountinfo->ban_client)
+ connection_add_banned_ip (client->connection.ip, mountinfo->ban_client);
config_release_config ();
client_send_403 (client, "mountpoint unavailable");
return;
@@ -546,7 +548,7 @@
{
auth_client *auth_user;
- if (mountinfo->auth->running == 0 || mountinfo->auth->pending_count > 1000)
+ if (mountinfo->auth->running == 0 || mountinfo->auth->pending_count > 150)
{
config_release_config ();
WARN0 ("too many clients awaiting authentication");
Modified: icecast/branches/kh/icecast/src/auth_url.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_url.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/auth_url.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -439,7 +439,7 @@
}
if (atd->location)
{
- client_send_302 (client, atd->location+10);
+ client_send_302 (client, atd->location);
auth_user->client = NULL;
free (atd->location);
atd->location = NULL;
Modified: icecast/branches/kh/icecast/src/cfgfile.c
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/cfgfile.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -791,6 +791,7 @@
{ "allow-url-ogg-metadata",
config_get_bool, &mount->url_ogg_meta },
{ "no-mount", config_get_bool, &mount->no_mount },
+ { "ban-client", config_get_int, &mount->ban_client },
{ "hidden", config_get_bool, &mount->hidden },
{ "authentication", auth_get_authenticator, &mount->auth },
{ "on-connect", config_get_str, &mount->on_connect },
@@ -841,7 +842,7 @@
if (mount->url_ogg_meta)
mount->ogg_passthrough = 0;
if (mount->queue_block_size < 100)
- mount->queue_block_size = 1400;
+ mount->queue_block_size = 2900;
mount->next = config->mounts;
config->mounts = mount;
Modified: icecast/branches/kh/icecast/src/cfgfile.h
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.h 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/cfgfile.h 2010-05-08 03:59:17 UTC (rev 17198)
@@ -98,6 +98,7 @@
int fallback_override; /* When this source arrives, do we steal back
clients from the fallback? */
+ int ban_client; /* do we add a client on this to the ban list automatically */
int no_mount; /* Do we permit direct requests of this mountpoint? (or only
indirect, through fallbacks) */
int burst_size; /* amount to send to a new client if possible, -1 take
Modified: icecast/branches/kh/icecast/src/client.c
===================================================================
--- icecast/branches/kh/icecast/src/client.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/client.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -55,7 +55,7 @@
if (sock != SOCK_ERROR)
{
refbuf_t *r;
- if (connection_init (&client->connection, sock) < 0)
+ if (connection_init (&client->connection, sock, NULL) < 0)
{
free (client);
return NULL;
Modified: icecast/branches/kh/icecast/src/connection.c
===================================================================
--- icecast/branches/kh/icecast/src/connection.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/connection.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -89,13 +89,20 @@
static int _handle_source_request (client_t *client);
static int _handle_stats_request (client_t *client);
+struct banned_entry
+{
+ char ip[16]; // may want to expand later for ipv6
+ time_t timeout;
+};
typedef struct
{
- char *filename;
time_t file_recheck;
time_t file_mtime;
avl_tree *contents;
+ int (*compare)(void *arg, void *a, void *b);
+ void (*add_new_entry)(avl_tree *t, const char *ip, time_t now);
+ char *filename;
} cache_file_contents;
static spin_t _connection_lock;
@@ -141,13 +148,15 @@
/* filtering client connection based on IP */
cache_file_contents banned_ip, allowed_ip;
+struct banned_entry *ban_entry_removal;
+
/* filtering listener connection based on useragent */
cache_file_contents useragents;
int connection_running = 0;
-static int compare_line (void *arg, void *a, void *b)
+static int compare_pattern (void *arg, void *a, void *b)
{
const char *value = (const char *)a;
const char *pattern = (const char *)b;
@@ -170,6 +179,15 @@
#endif
}
+static int compare_banned_ip (void *arg, void *a, void *b)
+{
+ struct banned_entry *this = (struct banned_entry *)a;
+ struct banned_entry *that = (struct banned_entry *)b;
+ if (that->timeout)
+ if (ban_entry_removal == NULL || that->timeout < ban_entry_removal->timeout)
+ ban_entry_removal = that; // identify possible removal
+ return compare_pattern (NULL, &this->ip[0] , &that->ip[0]);
+}
static int free_filtered_line (void*x)
{
@@ -320,7 +338,42 @@
return bytes;
}
+static void add_generic_text (avl_tree *t, const char *ip, time_t now)
+{
+ char *str = strdup (ip);
+ if (str)
+ avl_insert (t, str);
+}
+static void add_banned_ip (avl_tree *t, const char *ip, time_t now)
+{
+ struct banned_entry *entry = calloc (1, sizeof (struct banned_entry));
+ snprintf (&entry->ip[0], sizeof (entry->ip), "%s", ip);
+ if (now)
+ entry->timeout = now;
+ avl_insert (t, entry);
+}
+
+void connection_add_banned_ip (const char *ip, int duration)
+{
+ time_t timeout = -1;
+ if (duration > 0)
+ timeout = time(NULL) + duration;
+
+ if (banned_ip.contents)
+ {
+ global_lock();
+ add_banned_ip (banned_ip.contents, ip, timeout);
+ global_unlock();
+ }
+}
+
+void connection_stats (void)
+{
+ if (banned_ip.contents)
+ stats_event_args (NULL, "banned_IPs", "%ld", (long)banned_ip.contents->length);
+}
+
/* function to handle the re-populating of the avl tree containing IP addresses
* for deciding whether a connection of an incoming request is to be dropped.
*/
@@ -361,17 +414,14 @@
return;
}
- new_ips = avl_tree_new (compare_line, NULL);
+ new_ips = avl_tree_new (cache->compare, NULL);
while (get_line (file, line, MAX_LINE_LEN))
{
- char *str;
if(!line[0] || line[0] == '#')
continue;
count++;
- str = strdup (line);
- if (str)
- avl_insert (new_ips, str);
+ cache->add_new_entry (new_ips, line, 0);
}
fclose (file);
INFO2 ("%d entries read from file \"%s\"", count, cache->filename);
@@ -389,16 +439,41 @@
time_t now = time(NULL);
recheck_cached_file (&banned_ip, now);
- recheck_cached_file (&allowed_ip, now);
if (banned_ip.contents)
{
+ ban_entry_removal = NULL;
if (avl_get_by_key (banned_ip.contents, ip, &result) == 0)
{
- DEBUG1 ("%s is banned", ip);
- return 0;
+ struct banned_entry *entry = result;
+ if (entry->timeout)
+ {
+ if (entry->timeout > now)
+ {
+ /* we may need to extend the timeout, for repeat offenders */
+ if (now+900 > entry->timeout)
+ entry->timeout = now + 900;
+ return 0;
+ }
+ }
+ else
+ {
+ DEBUG1 ("%s is banned", ip);
+ return 0;
+ }
}
+ if (ban_entry_removal)
+ {
+ /* we have identified the entry with the earliest timeout, but has it expired */
+ if (ban_entry_removal->timeout <= now)
+ {
+ INFO1 ("removing %s from ban list for now", &ban_entry_removal->ip[0]);
+ avl_delete (banned_ip.contents, &ban_entry_removal->ip[0], free_filtered_line);
+ }
+ ban_entry_removal = NULL;
+ }
}
+ recheck_cached_file (&allowed_ip, now);
if (allowed_ip.contents)
{
if (avl_get_by_key (allowed_ip.contents, ip, &result) == 0)
@@ -416,7 +491,7 @@
}
-int connection_init (connection_t *con, sock_t sock)
+int connection_init (connection_t *con, sock_t sock, const char *addr)
{
if (con)
{
@@ -429,6 +504,11 @@
con->sock = sock;
if (sock == SOCK_ERROR)
return 0;
+ if (addr)
+ {
+ con->ip = strdup (addr);
+ return 0;
+ }
if (getpeername (sock, (struct sockaddr *)&sa, &slen) == 0)
{
char *ip;
@@ -468,6 +548,13 @@
#endif
}
+#ifdef HAVE_SIGNALFD
+void connection_close_sigfd (void)
+{
+ close (sigfd);
+}
+#endif
+
static sock_t wait_for_serversock (void)
{
#ifdef HAVE_POLL
@@ -627,6 +714,7 @@
}
global_unlock ();
sock_close (sock);
+ thread_sleep (1000);
return NULL;
}
@@ -841,10 +929,16 @@
#endif
banned_ip.filename = NULL;
banned_ip.file_mtime = 0;
+ banned_ip.add_new_entry = add_banned_ip;
+ banned_ip.compare = compare_banned_ip;
allowed_ip.filename = NULL;
allowed_ip.file_mtime = 0;
+ allowed_ip.add_new_entry = add_generic_text;
+ allowed_ip.compare = compare_pattern;
useragents.filename = NULL;
useragents.file_mtime = 0;
+ useragents.add_new_entry = add_generic_text;
+ useragents.compare = compare_pattern;
connection_running = 1;
INFO0 ("connection thread started");
@@ -1147,13 +1241,12 @@
return 1;
}
-static void check_for_filtering (ice_config_t *config, client_t *client)
+static void check_for_filtering (ice_config_t *config, client_t *client, char *uri)
{
- const char *uri = httpp_getvar (client->parser, HTTPP_VAR_URI);
char *pattern = config->access_log.exclude_ext;
char *extension = strrchr (uri, '.');
- if (extension == NULL || uri == NULL || pattern == NULL)
+ if (extension == NULL || pattern == NULL)
return;
extension++;
@@ -1189,7 +1282,7 @@
}
DEBUG1 ("start with %s", uri);
config = config_get_config();
- check_for_filtering (config, client);
+ check_for_filtering (config, client, uri);
port = config->port;
if (client->server_conn)
{
Modified: icecast/branches/kh/icecast/src/connection.h
===================================================================
--- icecast/branches/kh/icecast/src/connection.h 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/connection.h 2010-05-08 03:59:17 UTC (rev 17198)
@@ -57,9 +57,11 @@
void connection_thread_shutdown();
int connection_setup_sockets (struct ice_config_tag *config);
void connection_close(connection_t *con);
-int connection_init (connection_t *con, sock_t sock);
+int connection_init (connection_t *con, sock_t sock, const char *addr);
int connection_complete_source (struct source_tag *source, http_parser_t *parser);
void connection_uses_ssl (connection_t *con);
+void connection_add_banned_ip (const char *ip, int duration);
+void connection_stats (void);
#ifdef HAVE_OPENSSL
int connection_read_ssl (connection_t *con, void *buf, size_t len);
int connection_send_ssl (connection_t *con, const void *buf, size_t len);
@@ -72,6 +74,8 @@
int connection_check_relay_pass(http_parser_t *parser);
int connection_check_admin_pass(http_parser_t *parser);
+void connection_close_sigfd (void);
+
extern int connection_running;
#endif /* __CONNECTION_H__ */
Modified: icecast/branches/kh/icecast/src/format_mp3.c
===================================================================
--- icecast/branches/kh/icecast/src/format_mp3.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/format_mp3.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -545,11 +545,8 @@
return -1;
if (unprocessed > 0)
{
- /* make sure the new block has a minimum of queue_block_size */
- size_t len = unprocessed > source_mp3->queue_block_size ? unprocessed : source_mp3->queue_block_size;
- refbuf_t *leftover = refbuf_new (len);
- memcpy (leftover->data, refbuf->data + refbuf->len, unprocessed);
- leftover->len = unprocessed;
+ size_t len;
+ refbuf_t *leftover;
if (source_mp3->inline_metadata_interval > 0)
{
@@ -557,17 +554,22 @@
if (source_mp3->build_metadata_len == 0 && source_mp3->offset > unprocessed)
{
source_mp3->offset -= unprocessed;
- source_mp3->read_data = leftover;
- source_mp3->read_count = unprocessed;
}
else
+ {
+ leftover = refbuf_new (unprocessed);
+ memcpy (leftover->data, refbuf->data + refbuf->len, unprocessed);
+ leftover->len = unprocessed;
mpeg_data_insert (mpeg_sync, leftover); /* will need to merge this after metadata */
+ return 0;
+ }
}
- else
- {
- source_mp3->read_data = leftover;
- source_mp3->read_count = unprocessed;
- }
+ /* make sure the new block has a minimum of queue_block_size */
+ len = unprocessed > source_mp3->queue_block_size ? unprocessed : source_mp3->queue_block_size;
+ leftover = refbuf_new (len);
+ memcpy (leftover->data, refbuf->data + refbuf->len, unprocessed);
+ source_mp3->read_data = leftover;
+ source_mp3->read_count = unprocessed;
}
return 0;
}
Modified: icecast/branches/kh/icecast/src/fserve.c
===================================================================
--- icecast/branches/kh/icecast/src/fserve.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/fserve.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -75,6 +75,8 @@
fbinfo finfo;
mutex_t lock;
int refcount;
+ int peak;
+ int max;
FILE *fp;
time_t stats_update;
format_plugin_t *format;
@@ -198,7 +200,6 @@
}
if (fh->fp)
fclose (fh->fp);
- stats_event (fh->finfo.mount, NULL, NULL);
if (fh->format)
{
format_plugin_clear (fh->format, NULL);
@@ -238,7 +239,14 @@
if (client)
{
if (finfo->mount && (finfo->flags & FS_FALLBACK))
+ {
stats_event_args (result->finfo.mount, "listeners", "%ld", result->refcount);
+ if (result->refcount > result->peak)
+ {
+ result->peak = result->refcount;
+ stats_event_flags (result->finfo.mount, "listener_peak", "%ld", result->peak);
+ }
+ }
avl_insert (result->clients, client);
if (result->format)
{
@@ -281,7 +289,7 @@
{
char *contenttype = fserve_content_type (fullpath);
- stats_event_flags (finfo->mount, "file", fullpath, STATS_HIDDEN);
+ stats_event (finfo->mount, "fallback", "file");
fh->format = calloc (1, sizeof (format_plugin_t));
fh->format->type = format_get_type (contenttype);
free (contenttype);
@@ -305,10 +313,14 @@
thread_mutex_lock (&fh->lock);
fh->clients = avl_tree_new (client_compare, NULL);
fh->refcount = 1;
+ fh->peak = 1;
if (client)
{
if (finfo->mount && (finfo->flags & FS_FALLBACK))
+ {
stats_event_flags (fh->finfo.mount, "listeners", "1", STATS_HIDDEN);
+ stats_event_flags (fh->finfo.mount, "listener_peak", "1", STATS_HIDDEN);
+ }
avl_insert (fh->clients, client);
}
fh->finfo.mount = strdup (finfo->mount);
@@ -600,6 +612,8 @@
if (fh->finfo.flags & FS_FALLBACK)
stats_event_dec (NULL, "listeners");
remove_from_fh (fh, client);
+ if (fh->refcount == 1)
+ stats_event (fh->finfo.mount, NULL, NULL);
fh_release (fh);
}
if (client->respcode == 200)
@@ -645,6 +659,8 @@
client->shared_data = NULL;
thread_mutex_lock (&fh->lock);
remove_from_fh (fh, client);
+ if (fh->refcount == 1)
+ stats_event (fh->finfo.mount, NULL, NULL);
f.flags = fh->finfo.flags;
f.limit = fh->finfo.limit;
f.mount = fh->finfo.fallback;
@@ -824,7 +840,7 @@
if (fh->stats_update <= now)
{
stats_event_args (fh->finfo.mount, "outgoing_kbitrate", "%ld",
- (8 * rate_avg (fh->format->out_bitrate))/1024);
+ (long)((8 * rate_avg (fh->format->out_bitrate))/1024));
fh->stats_update = now + 5;
}
if (client->pos == refbuf->len)
@@ -1086,22 +1102,61 @@
}
+int fserve_list_clients_xml (xmlNodePtr srcnode, fbinfo *finfo)
+{
+ int ret = 0;
+ fh_node *fh = open_fh (finfo, NULL);
+
+ if (fh)
+ {
+ avl_node *anode = avl_get_first (fh->clients);
+
+ while (anode)
+ {
+ client_t *listener = (client_t *)anode->key;
+ char buf [100];
+
+ 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);
+ }
+
+ ret++;
+ anode = avl_get_next (anode);
+ }
+ fh_release (fh);
+ }
+ return ret;
+}
+
+
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");
+ int ret;
fbinfo finfo;
xmlDocPtr doc;
xmlNodePtr node, srcnode;
- char buf[100];
- finfo.flags = 0;
- if (type && strcmp (type, "fallback") == 0)
- {
- finfo.flags = FS_FALLBACK;
- c = 1;
- }
+ finfo.flags = FS_FALLBACK;
finfo.mount = (char*)mount;
finfo.limit = 0;
finfo.fallback = NULL;
@@ -1112,56 +1167,17 @@
srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL);
xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(mount));
- while (c)
+ ret = fserve_list_clients_xml (srcnode, &finfo);
+ if (ret == 0)
{
- fh_node *fh = open_fh (&finfo, NULL);
- if (fh)
- {
- avl_node *node = avl_get_first (fh->clients);
-
- while (node)
- {
- client_t *listener = (client_t *)node->key;
-
- 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++;
- node = avl_get_next (node);
- }
- fh_release (fh);
- }
- c--;
- finfo.flags = FS_FALLBACK;
+ finfo.flags = 0;
+ ret = fserve_list_clients_xml (srcnode, &finfo);
}
- if (entries)
+ if (ret)
{
- snprintf (buf, sizeof(buf), "%u", entries);
- xmlNewChild(srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));
+ char buf[20];
+ snprintf (buf, sizeof(buf), "%u", ret);
+ xmlNewChild (srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));
admin_send_response (doc, client, response, "listclients.xsl");
}
else
Modified: icecast/branches/kh/icecast/src/fserve.h
===================================================================
--- icecast/branches/kh/icecast/src/fserve.h 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/fserve.h 2010-05-08 03:59:17 UTC (rev 17198)
@@ -40,6 +40,7 @@
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);
+int fserve_list_clients_xml (xmlNodePtr srcnode, fbinfo *finfo);
void fserve_kill_client (client_t *client, const char *mount, int response);
extern int fserve_running;
Modified: icecast/branches/kh/icecast/src/global.c
===================================================================
--- icecast/branches/kh/icecast/src/global.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/global.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -47,7 +47,6 @@
#endif
thread_mutex_create(&_global_mutex);
thread_spin_create (&global.spinlock);
- thread_rwlock_create (&global.shutdown_lock);
global.out_bitrate = rate_setup (20000, 1000);
}
@@ -55,7 +54,6 @@
{
thread_mutex_destroy(&_global_mutex);
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);
Modified: icecast/branches/kh/icecast/src/global.h
===================================================================
--- icecast/branches/kh/icecast/src/global.h 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/global.h 2010-05-08 03:59:17 UTC (rev 17198)
@@ -39,7 +39,6 @@
int schedule_config_reread;
avl_tree *source_tree;
- rwlock_t shutdown_lock;
#ifdef MY_ALLOC
avl_tree *alloc_tree;
Modified: icecast/branches/kh/icecast/src/main.c
===================================================================
--- icecast/branches/kh/icecast/src/main.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/main.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -118,6 +118,7 @@
slave_shutdown();
fserve_shutdown();
stats_shutdown();
+ stop_logging();
config_shutdown();
refbuf_shutdown();
@@ -222,7 +223,6 @@
slave_initialize();
connection_setup_sockets (NULL);
- stop_logging();
}
/* chroot the process. Watch out - we need to do this before starting other
Modified: icecast/branches/kh/icecast/src/mpeg.c
===================================================================
--- icecast/branches/kh/icecast/src/mpeg.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/mpeg.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -113,23 +113,33 @@
}
+/* return -1 for no valid frame at this specified address, 0 for more data needed */
static int get_initial_frame (struct mpeg_sync *mp, unsigned char *p, unsigned remaining)
{
if (p[1] < 0xE0)
- return 0;
+ return -1;
mp->layer = (p[1] & 0x6) >> 1;
//nocrc = p[1] & 0x1;
if (mp->layer == 0 && (p[1] >= 0xF0))
{
- int frame_len;
int samplerate_idx = (p[2] & 0x3C) >> 2,
v = (p[2] << 8) + p[3],
channels_idx = (v & 0x1C0) >> 6;
int id = p[1] & 0x8;
+ int checking = 3;
+ unsigned char *fh = p;
- frame_len = get_aac_frame_len (p);
- if (frame_len >= remaining || p[frame_len] != 255)
- return -1;
+ while (checking)
+ {
+ int frame_len = get_aac_frame_len (fh);
+ if (frame_len+5 >= remaining)
+ return 0;
+ if (fh[frame_len] != 255 || fh[frame_len+1] != p[1])
+ return -1;
+ remaining -= frame_len;
+ fh += frame_len;
+ checking--;
+ }
// profile = p[1] & 0xC0;
mp->samplerate = aacp_sample_freq [samplerate_idx];
mp->channels = aacp_num_channels [channels_idx];
@@ -140,7 +150,6 @@
}
mp->syncbytes = 3;
memcpy (&mp->fixed_headerbits[0], p, 3);
- //mp->samplerate <<= 1;
DEBUG3 ("detected AAC MPEG-%s, rate %d, channels %d", id ? "2" : "4", mp->samplerate, mp->channels);
mp->process_frame = handle_aac_frame;
return 1;
@@ -152,7 +161,8 @@
mp->ver = (p[1] & 0x18) >> 3;
if (mp->layer && version [mp->ver] && layer[mp->layer])
{
- int frame_len;
+ int checking = 4;
+ unsigned char *fh = p;
int samplerates [4][4] = {
{ 11025, 0, 22050, 44100},
{ 12000, 0, 24000, 48000 },
@@ -163,24 +173,31 @@
mp->samplerate = samplerates [(p[2]&0xC) >> 2][mp->ver];
if (mp->samplerate == 0)
return -1;
- frame_len = get_frame_samples (mp, p);
- if (frame_len > 0)
+ while (checking)
{
- if (frame_len >= remaining || p[frame_len] != 255)
+ int frame_len = get_frame_samples (mp, fh);
+ if (frame_len <= 0)
return -1;
- if (((p[3] & 0xC0) >> 6) == 3)
- mp->channels = 1;
- else
- mp->channels = 2;
- mp->syncbytes = 2;
- memcpy (&mp->fixed_headerbits[0], p, 2);
- //DEBUG4 ("%s %s detected (%d, %d)", version [mp->ver], layer[mp->layer], mp->samplerate, mp->channels);
- mp->process_frame = handle_mpeg_frame;
- return 1;
+ if (frame_len+4 >= remaining)
+ return 0;
+ if (fh[frame_len] != 255 || fh[frame_len+1] != p[1])
+ return -1;
+ remaining -= frame_len;
+ fh += frame_len;
+ checking--;
}
+ if (((p[3] & 0xC0) >> 6) == 3)
+ mp->channels = 1;
+ else
+ mp->channels = 2;
+ mp->syncbytes = 2;
+ memcpy (&mp->fixed_headerbits[0], p, 2);
+ DEBUG4 ("%s %s detected (%d, %d)", version [mp->ver], layer[mp->layer], mp->samplerate, mp->channels);
+ mp->process_frame = handle_mpeg_frame;
+ return 1;
}
}
- return 0;
+ return -1;
}
@@ -219,11 +236,11 @@
}
start = (unsigned char *)new_block->data + offset;
remaining = new_block->len - offset;
- end = start + remaining;
+ end = (unsigned char*)new_block->data + new_block->len;
while (1)
{
remaining = end - start;
- if (remaining < 10)
+ if (remaining < 10) /* make sure we have some bytes to check */
break;
if (*start != 255)
{
@@ -232,21 +249,26 @@
if (ret == remaining)
break; // no sync in the rest, so dump it
new_block->len -= (remaining - ret);
- remaining = ret;
- end = start + remaining;
+ end = (unsigned char*)new_block->data + new_block->len;
+ continue;
}
if (mp->syncbytes == 0)
{
- if (get_initial_frame (mp, start, remaining) <= 0)
+ int ret = get_initial_frame (mp, start, remaining);
+ if (ret < 0)
{
- // no a complete frame not here, try again
- start++;
+ // failed to detect a complete frame, try again
+ memmove (start, start+1, remaining-1);
+ end--;
continue;
}
+ if (ret == 0)
+ break;
}
if (memcmp (start, &mp->fixed_headerbits[0], mp->syncbytes) != 0)
{
- start++;
+ memmove (start, start+1, remaining-1);
+ end--;
continue;
}
frame_len = mp->process_frame (mp, start, remaining);
@@ -256,7 +278,13 @@
completed++;
}
if (completed == 0)
- return -1;
+ {
+ /* none found, so either shrink it or drop it */
+ if (remaining > 1500)
+ remaining = 1500;
+ else
+ return -1;
+ }
new_block->len -= remaining;
return remaining;
}
Modified: icecast/branches/kh/icecast/src/mpeg.h
===================================================================
--- icecast/branches/kh/icecast/src/mpeg.h 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/mpeg.h 2010-05-08 03:59:17 UTC (rev 17198)
@@ -19,7 +19,7 @@
typedef struct mpeg_sync
{
unsigned char fixed_headerbits[3];
- int syncbytes;
+ char syncbytes;
int (*process_frame) (struct mpeg_sync *mp, unsigned char *p, int len);
refbuf_t *surplus;
int ver;
Modified: icecast/branches/kh/icecast/src/slave.c
===================================================================
--- icecast/branches/kh/icecast/src/slave.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/slave.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -112,7 +112,7 @@
{
relay_server *next = relay->next;
- DEBUG1("freeing relay %s", relay->localmount);
+ DEBUG2("freeing relay %s (%p)", relay->localmount, relay);
if (relay->source)
source_free_source (relay->source);
while (relay->masters)
@@ -165,6 +165,7 @@
copy->enable = r->enable;
copy->source = r->source;
r->source = NULL;
+ DEBUG1 ("copy relay at %p", copy);
}
return copy;
}
@@ -293,27 +294,65 @@
}
+static http_parser_t *get_relay_response (connection_t *con, const char *mount,
+ const char *server, int ask_for_metadata, const char *auth_header)
+{
+ ice_config_t *config = config_get_config ();
+ char *server_id = strdup (config->server_id);
+ http_parser_t *parser = NULL;
+ char response [4096];
+
+ config_release_config ();
+
+ /* At this point we may not know if we are relaying an mp3 or vorbis
+ * stream, but only send the icy-metadata header if the relay details
+ * state so (the typical case). It's harmless in the vorbis case. If
+ * we don't send in this header then relay will not have mp3 metadata.
+ */
+ sock_write (con->sock, "GET %s HTTP/1.0\r\n"
+ "User-Agent: %s\r\n"
+ "Host: %s\r\n"
+ "%s"
+ "%s"
+ "\r\n",
+ mount,
+ server_id,
+ server,
+ ask_for_metadata ? "Icy-MetaData: 1\r\n" : "",
+ auth_header ? auth_header : "");
+
+ free (server_id);
+ memset (response, 0, sizeof(response));
+ if (util_read_header (con->sock, response, 4096, READ_ENTIRE_HEADER) == 0)
+ {
+ INFO0 ("Header read failure");
+ return NULL;
+ }
+ parser = httpp_create_parser();
+ httpp_initialize (parser, NULL);
+ if (! httpp_parse_response (parser, response, strlen(response), mount))
+ {
+ INFO0 ("problem parsing response from relay");
+ httpp_destroy (parser);
+ return NULL;
+ }
+ return parser;
+}
+
+
/* Actually open the connection and do some http parsing, handle any 302
* responses within here.
*/
static int open_relay_connection (client_t *client, relay_server *relay, relay_server_master *master)
{
int redirects = 0;
- char *server_id = NULL;
- ice_config_t *config;
http_parser_t *parser = NULL;
connection_t *con = &client->connection;
char *server = strdup (master->ip);
char *mount = strdup (master->mount);
- int port = master->port;
- char *bind = NULL;
- char *auth_header;
- char header[4096];
+ int port = master->port, timeout = master->timeout, ask_for_metadata = relay->mp3metadata;
+ char *auth_header = NULL;
- config = config_get_config ();
- server_id = strdup (config->server_id);
- config_release_config ();
-
if (relay->username && relay->password)
{
char *esc_authorisation;
@@ -329,57 +368,42 @@
"Authorization: Basic %s\r\n", esc_authorisation);
free(esc_authorisation);
}
- else
- auth_header = strdup ("");
while (redirects < 10)
{
sock_t streamsock;
+ char *bind = NULL;
/* policy decision, we assume a source bind even after redirect, possible option */
if (master->bind)
- bind = master->bind;
+ bind = strdup (master->bind);
if (bind)
INFO4 ("connecting to %s:%d for %s, bound to %s", server, port, relay->localmount, bind);
else
INFO3 ("connecting to %s:%d for %s", server, port, relay->localmount);
- streamsock = sock_connect_wto_bind (server, port, bind, master->timeout);
- if (streamsock == SOCK_ERROR)
+ thread_mutex_unlock (&client->worker->lock);
+ streamsock = sock_connect_wto_bind (server, port, bind, timeout);
+ free (bind);
+ if (streamsock == SOCK_ERROR || connection_init (con, streamsock, server) < 0)
{
- WARN3 ("Failed to connect to %s:%d for %s", server, port, relay->localmount);
+ WARN2 ("Failed to connect to %s:%d", server, port);
+ thread_mutex_lock (&client->worker->lock);
break;
}
- connection_init (con, streamsock);
- /* At this point we may not know if we are relaying an mp3 or vorbis
- * stream, but only send the icy-metadata header if the relay details
- * state so (the typical case). It's harmless in the vorbis case. If
- * we don't send in this header then relay will not have mp3 metadata.
- */
- sock_write(streamsock, "GET %s HTTP/1.0\r\n"
- "User-Agent: %s\r\n"
- "Host: %s\r\n"
- "%s"
- "%s"
- "\r\n",
- mount,
- server_id,
- server,
- 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)
+ parser = get_relay_response (con, mount, server, ask_for_metadata, auth_header);
+
+ thread_mutex_lock (&client->worker->lock);
+ if (relay != client->shared_data) /* unusual but possible */
{
- ERROR4 ("Header read failed for %s (%s:%d%s)", relay->localmount, server, port, mount);
+ INFO0 ("detected relay change, retrying");
break;
}
- parser = httpp_create_parser();
- httpp_initialize (parser, NULL);
- if (! httpp_parse_response (parser, header, strlen(header), relay->localmount))
+ if (parser == NULL)
{
- ERROR4("Error parsing relay request for %s (%s:%d%s)", relay->localmount,
+ ERROR4 ("Problem trying to start relay on %s (%s:%d%s)", relay->localmount,
server, port, mount);
break;
}
@@ -414,6 +438,8 @@
}
else
{
+ http_parser_t *old_parser = client->parser;
+
if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE))
{
ERROR2("Error from relay request: %s (%s)", relay->localmount,
@@ -422,10 +448,11 @@
}
sock_set_blocking (streamsock, 0);
client->parser = parser;
+ if (old_parser)
+ httpp_destroy (old_parser);
client_set_queue (client, NULL);
free (server);
free (mount);
- free (server_id);
free (auth_header);
return 0;
@@ -435,7 +462,6 @@
/* failed, better clean up */
free (server);
free (mount);
- free (server_id);
free (auth_header);
connection_close (con);
if (parser)
@@ -460,6 +486,8 @@
ret = open_relay_connection (client, relay, master);
thread_mutex_lock (&src->lock);
+ if (relay != client->shared_data) // relay data changed, retry with new data
+ return open_relay (client->shared_data);
if (ret < 0)
continue;
source_clear_source (src); // clear any old data
@@ -477,9 +505,9 @@
static void *start_relay_stream (void *arg)
{
- relay_server *relay = arg;
- source_t *src = relay->source;
- client_t *client = src->client;
+ client_t *client = arg;
+ relay_server *relay;
+ source_t *src;
int failed = 1, sources;
global_lock();
@@ -490,7 +518,10 @@
{
ice_config_t *config = config_get_config();
- thread_rwlock_rlock (&global.shutdown_lock);
+ thread_mutex_lock (&client->worker->lock);
+ relay = client->shared_data;
+ src = relay->source;
+
thread_mutex_lock (&src->lock);
src->flags |= SOURCE_PAUSE_LISTENERS;
if (sources > config->source_limit)
@@ -509,6 +540,7 @@
failed = 0;
} while (0);
+ relay = client->shared_data; // relay may of changed during open_relay
relay->running = 1;
client->ops = &relay_client_ops;
client->schedule_ms = timing_get_time();
@@ -533,7 +565,6 @@
relays_connecting--;
thread_spin_unlock (&relay_start_lock);
- thread_mutex_lock (&client->worker->lock);
client->flags |= CLIENT_ACTIVE;
thread_cond_signal (&client->worker->cond);
thread_mutex_unlock (&client->worker->lock);
@@ -922,11 +953,11 @@
if (curl_easy_perform (handle) != 0)
WARN2 ("Failed URL access \"%s\" (%s)", url, error);
}
- /* process retrieved relays */
+ /* merge retrieved relays */
thread_mutex_lock (&(config_locks()->relay_lock));
cleanup_relays = update_relays (&global.master_relays, master->new_relays);
- relay_check_streams (global.master_relays, cleanup_relays, 0);
+ relay_check_streams (global.master_relays, cleanup_relays, 1);
relay_check_streams (NULL, master->new_relays, 0);
thread_mutex_unlock (&(config_locks()->relay_lock));
@@ -1095,8 +1126,6 @@
global.master_relays = NULL;
redirector_clearall();
- thread_rwlock_wlock (&global.shutdown_lock);
- thread_rwlock_unlock (&global.shutdown_lock);
INFO0 ("Slave thread shutdown complete");
}
@@ -1247,37 +1276,39 @@
}
DEBUG1 ("all listeners have now been checked on %s", relay->localmount);
source->flags &= ~SOURCE_TERMINATING;
- client->ops = &relay_startup_ops;
if (relay->running && relay->enable)
{
INFO1 ("standing by to restart relay on %s", relay->localmount);
connection_close (&client->connection);
- if (client->parser)
- httpp_destroy (client->parser);
- client->parser = NULL;
thread_mutex_unlock (&source->lock);
ret = 0;
}
else
{
+ if (source->listeners)
+ {
+ INFO1 ("listeners on terminating relay %s, rechecking", relay->localmount);
+ thread_mutex_unlock (&source->lock);
+ return 0; /* listeners may be paused, recheck and let them leave this stream */
+ }
INFO1 ("shutting down relay %s", relay->localmount);
if (relay->enable == 0)
{
source_clear_source (source);
- source_clear_listeners (source);
relay->running = 0;
ret = 0;
}
+ source_clear_listeners (source);
thread_mutex_unlock (&source->lock);
stats_event (relay->localmount, NULL, NULL); // needed???
slave_update_all_mounts();
}
+ client->ops = &relay_startup_ops;
global_lock();
global.sources--;
stats_event_args (NULL, "sources", "%d", global.sources);
global_unlock();
global_reduce_bitrate_sampling (global.out_bitrate);
- thread_rwlock_unlock (&global.shutdown_lock);
return ret;
}
@@ -1295,7 +1326,13 @@
relay_server *relay = client->shared_data;
if (relay->cleanup)
+ {
+ source_t *source = relay->source;
+ thread_mutex_lock (&source->lock);
+ source_clear_listeners (source);
+ thread_mutex_unlock (&source->lock);
return -1;
+ }
if (global.running != ICE_RUNNING)
return 0; /* wait for cleanup */
if (relay->enable == 0 || relay->start > client->worker->current_time.tv_sec)
@@ -1307,15 +1344,31 @@
if (relay->on_demand)
{
source_t *src = relay->source;
+ int start_relay = src->listeners; // 0 or non-zero
+
src->flags |= SOURCE_ON_DEMAND;
if (client->worker->current_time.tv_sec % 10 == 0)
{
mount_proxy * mountinfo = config_find_mount (config_get_config(), src->mount);
if (mountinfo && mountinfo->fallback_mount)
- source_set_override (mountinfo->fallback_mount, src->mount);
+ {
+ source_t *fallback;
+ avl_tree_rlock (global.source_tree);
+ fallback = source_find_mount (mountinfo->fallback_mount);
+ if (fallback)
+ {
+ if (strcmp (fallback->mount, src->mount) != 0)
+ {
+ // if there are listeners not already being moved
+ if (fallback->listeners && fallback->fallback.mount == NULL)
+ start_relay = 1;
+ }
+ }
+ avl_tree_unlock (global.source_tree);
+ }
config_release_config();
}
- if (src->listeners == 0)
+ if (start_relay == 0)
{
client->schedule_ms = client->worker->time_ms + 1000;
return 0;
@@ -1328,14 +1381,14 @@
if (relays_connecting > 3)
{
thread_spin_unlock (&relay_start_lock);
- client->schedule_ms = client->worker->time_ms + 2000;
+ client->schedule_ms = client->worker->time_ms + 1000;
return 0;
}
relays_connecting++;
thread_spin_unlock (&relay_start_lock);
client->flags &= ~CLIENT_ACTIVE;
- thread_create ("Relay Thread", start_relay_stream, relay, THREAD_DETACHED);
+ thread_create ("Relay Thread", start_relay_stream, client, THREAD_DETACHED);
return 0;
}
Modified: icecast/branches/kh/icecast/src/source.c
===================================================================
--- icecast/branches/kh/icecast/src/source.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/source.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -350,7 +350,7 @@
/* There should be no listeners on this mount */
if (source->listeners)
- WARN1("active listeners on mountpoint %s", source->mount);
+ WARN3("active listeners on mountpoint %s (%ld, %ld)", source->mount, source->listeners, source->termination_count);
avl_tree_free (source->clients, NULL);
thread_mutex_destroy (&source->lock);
@@ -368,7 +368,7 @@
{
INFO1 ("source %s to be freed", source->mount);
avl_tree_wlock (global.source_tree);
- INFO1 ("removing source %s from tree", source->mount);
+ DEBUG1 ("removing source %s from tree", source->mount);
avl_delete (global.source_tree, source, _free_source);
avl_tree_unlock (global.source_tree);
}
@@ -443,6 +443,8 @@
source->fallback.mount = NULL;
source->flags &= ~SOURCE_TEMPORARY_FALLBACK;
}
+ if (source->listeners == 0)
+ rate_add (source->format->out_bitrate, 0, client->worker->time_ms);
if (source->prev_listeners != source->listeners)
{
INFO2("listener count on %s now %lu", source->mount, source->listeners);
@@ -850,13 +852,8 @@
int ret = 0;
if (client->connection.error)
- {
- /* if listener disconnects at the same time as the source does then we need
- * to account for it as the source thinks it is still connected */
- if (source->termination_count)
- source->termination_count--;
return -1;
- }
+
if (source->fallback.mount)
{
int move_failed;
@@ -875,10 +872,10 @@
}
if (source->flags & SOURCE_TERMINATING)
{
- source->termination_count--;
DEBUG2 ("termination count on %s now %lu", source->mount, source->termination_count);
if ((source->flags & SOURCE_PAUSE_LISTENERS) && global.running == ICE_RUNNING)
{
+ source->termination_count--;
if (client->refbuf && (client->refbuf->flags & SOURCE_QUEUE_BLOCK))
client_set_queue (client, NULL);
client->ops = &listener_pause_ops;
@@ -1085,7 +1082,7 @@
void source_set_fallback (source_t *source, const char *dest_mount)
{
int bitrate = (int)(rate_avg (source->format->in_bitrate) * 1.02);
- if (dest_mount == NULL || bitrate == 0)
+ if (dest_mount == NULL)
return;
source->fallback.flags = FS_FALLBACK;
@@ -1443,7 +1440,6 @@
global_unlock();
return -1;
}
- thread_rwlock_rlock (&global.shutdown_lock);
agent = httpp_getvar (source->client->parser, "user-agent");
if (agent)
@@ -1644,7 +1640,6 @@
thread_mutex_unlock (&source->lock);
source_free_source (source);
- thread_rwlock_unlock (&global.shutdown_lock);
slave_update_all_mounts();
client_destroy (client);
}
@@ -1661,6 +1656,11 @@
if (source->listeners == 0)
rate_reduce (source->format->out_bitrate, 1000);
+ /* if listener disconnects at the same time as the source does then we need
+ * to account for it as the source thinks it is still connected */
+ if (source->termination_count)
+ source->termination_count--;
+
stats_event_dec (NULL, "listeners");
stats_event_args (source->mount, "listeners", "%lu", source->listeners);
/* change of listener numbers, so reduce scope of global sampling */
Modified: icecast/branches/kh/icecast/src/stats.c
===================================================================
--- icecast/branches/kh/icecast/src/stats.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/stats.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -1021,9 +1021,20 @@
thread_mutex_lock (&source->lock);
admin_source_listeners (source, node);
thread_mutex_unlock (&source->lock);
+ avl_tree_unlock (global.source_tree);
}
+ else
+ {
+ fbinfo finfo;
- avl_tree_unlock (global.source_tree);
+ avl_tree_unlock (global.source_tree);
+ finfo.flags = FS_FALLBACK;
+ finfo.mount = (char*)show_mount;
+ finfo.limit = 0;
+ finfo.fallback = NULL;
+
+ fserve_list_clients_xml (node, &finfo);
+ }
}
return doc;
}
@@ -1135,10 +1146,10 @@
if (source == NULL)
{
- stats_node_t *node = _find_node (src->stats_tree, "file");
+ stats_node_t *node = _find_node (src->stats_tree, "fallback");
if (node == NULL)
{
- /* no source_t and no fallbakc file stat, so delete */
+ /* no source_t and no fallback file stat, so delete */
snode = avl_get_next (snode);
avl_delete (_stats.source_tree, src, _free_source_stats);
continue;
@@ -1158,6 +1169,7 @@
avl_node *anode;
char buffer [VAL_BUFSIZE];
+ connection_stats ();
anode = avl_get_first(_stats.global_tree);
while (anode)
{
Modified: icecast/branches/kh/icecast/src/xslt.c
===================================================================
--- icecast/branches/kh/icecast/src/xslt.c 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/src/xslt.c 2010-05-08 03:59:17 UTC (rev 17198)
@@ -125,7 +125,8 @@
}
}
- xsltFreeStylesheet(cache[oldest].stylesheet);
+ if (cache[oldest].stylesheet)
+ xsltFreeStylesheet(cache[oldest].stylesheet);
free(cache[oldest].filename);
return oldest;
Modified: icecast/branches/kh/icecast/win32/icecast2.iss
===================================================================
--- icecast/branches/kh/icecast/win32/icecast2.iss 2010-05-05 23:28:15 UTC (rev 17197)
+++ icecast/branches/kh/icecast/win32/icecast2.iss 2010-05-08 03:59:17 UTC (rev 17198)
@@ -3,7 +3,7 @@
[Setup]
AppName=Icecast2-KH
-AppVerName=Icecast v2.3.2-kh22
+AppVerName=Icecast v2.3.2-kh23
AppPublisherURL=http://www.icecast.org
AppSupportURL=http://www.icecast.org
AppUpdatesURL=http://www.icecast.org
@@ -13,7 +13,7 @@
LicenseFile=..\COPYING
InfoAfterFile=..\README
OutputDir=.
-OutputBaseFilename=icecast2_win32_v2.3.2-kh22_setup
+OutputBaseFilename=icecast2_win32_v2.3.2-kh23_setup
WizardImageFile=icecast2logo2.bmp
WizardImageStretch=no
VersionInfoVersion=2.3.2
@@ -72,3 +72,6 @@
+
+
+
More information about the commits
mailing list