1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-11-03 04:17:17 -05:00

bump version. the most significant things are the stats thread removal and a theora fix.

svn path=/icecast/branches/kh/icecast/; revision=15145
This commit is contained in:
Karl Heyes 2008-08-01 20:26:09 +00:00
parent f3e87bfdc3
commit 386a554a72
17 changed files with 201 additions and 233 deletions

10
NEWS
View File

@ -15,6 +15,16 @@ Feature differences from SVN trunk
any extra tags are show in the conf/icecast.xml.dist file any extra tags are show in the conf/icecast.xml.dist file
2.3.2-kh1
. remove stats thread. Stats clients still have their own thread and queue.
. fix low bandwidth theora stream problem.
. failing on-demand relays were not being recovered as they should of.
. encode xml entity data for clients useragent/username
. reduce memory usage in avl nodes, seems to benefit win32 more because of the
unused lock handling
. minor patch for kate detection applied. ogg.k.ogg.k
. minor type cleanup for off_t in fserve
2.3-kh34 2.3-kh34
. Added Kate/Skeleton codec handling within Ogg streams. patch by ogg.k.ogg.k . Added Kate/Skeleton codec handling within Ogg streams. patch by ogg.k.ogg.k
. small changes for stream directory handling, mostly for error cases. . small changes for stream directory handling, mostly for error cases.

View File

@ -95,7 +95,7 @@
#define PACKAGE_NAME "Icecast" #define PACKAGE_NAME "Icecast"
/* Version number of package */ /* Version number of package */
#define VERSION "2.3-kh34" #define VERSION "2.3.2-kh1"
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION VERSION #define PACKAGE_VERSION VERSION
@ -139,6 +139,8 @@ typedef unsigned int socklen_t;
#define fseeko fseek #define fseeko fseek
#define PRIdMAX "ld" #define PRIdMAX "ld"
#define SCNdMAX "ld" #define SCNdMAX "ld"
#define SCN_OFF_T "ld"
#define PRI_OFF_T "ld"
#define PRId64 "I64d" #define PRId64 "I64d"
#define PRIu64 "I64u" #define PRIu64 "I64u"
@ -157,3 +159,6 @@ typedef unsigned int socklen_t;
#define sock_t SOCKET #define sock_t SOCKET
/* time format for strftime */
#define ICECAST_TIME_FMT "%a, %d %b %Y %H:%M:%S"

View File

@ -1,4 +1,4 @@
AC_INIT([Icecast], [2.3-kh34], [karl@xiph.org]) AC_INIT([Icecast], [2.3.2-kh1], [karl@xiph.org])
AC_PREREQ(2.59) AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(src/main.c) AC_CONFIG_SRCDIR(src/main.c)
@ -135,6 +135,7 @@ XIPH_PATH_OPENSSL([
ICECAST_OPTIONAL="$ICECAST_OPTIONAL auth_cmd.o" ICECAST_OPTIONAL="$ICECAST_OPTIONAL auth_cmd.o"
AC_DEFINE([MIMETYPESFILE],"/etc/mime.types", [Default location of mime types file]) AC_DEFINE([MIMETYPESFILE],"/etc/mime.types", [Default location of mime types file])
AC_DEFINE([ICECAST_TIME_FMT],["%a, %d %b %Y %H:%M:%S %z"], [time format for strftime])
dnl Make substitutions dnl Make substitutions

View File

@ -632,7 +632,12 @@ static void add_listener_node (xmlNodePtr srcnode, client_t *listener)
xmlNewChild (node, NULL, XMLSTR("ip"), XMLSTR(listener->con->ip)); xmlNewChild (node, NULL, XMLSTR("ip"), XMLSTR(listener->con->ip));
useragent = httpp_getvar (listener->parser, "user-agent"); useragent = httpp_getvar (listener->parser, "user-agent");
xmlNewChild (node, NULL, XMLSTR("useragent"), XMLSTR(useragent)); if (useragent)
{
xmlChar *str = xmlEncodeEntitiesReentrant (srcnode->doc, XMLSTR(useragent));
xmlNewChild (node, NULL, XMLSTR("useragent"), str);
xmlFree (str);
}
snprintf (buf, sizeof (buf), "%u", listener->lag); snprintf (buf, sizeof (buf), "%u", listener->lag);
xmlNewChild (node, NULL, XMLSTR("lag"), XMLSTR(buf)); xmlNewChild (node, NULL, XMLSTR("lag"), XMLSTR(buf));
@ -641,7 +646,11 @@ static void add_listener_node (xmlNodePtr srcnode, client_t *listener)
(unsigned long)(global.time - listener->con->con_time)); (unsigned long)(global.time - listener->con->con_time));
xmlNewChild (node, NULL, XMLSTR("connected"), XMLSTR(buf)); xmlNewChild (node, NULL, XMLSTR("connected"), XMLSTR(buf));
if (listener->username) if (listener->username)
xmlNewChild (node, NULL, XMLSTR("username"), XMLSTR(listener->username)); {
xmlChar *str = xmlEncodeEntitiesReentrant (srcnode->doc, XMLSTR(listener->username));
xmlNewChild (node, NULL, XMLSTR("username"), str);
xmlFree (str);
}
} }

View File

@ -1120,8 +1120,6 @@ void source_startup (client_t *client, const char *uri, int auth_style)
static void _handle_stats_request (client_t *client, char *uri) static void _handle_stats_request (client_t *client, char *uri)
{ {
stats_event_inc(NULL, "stats_connections");
if (connection_check_admin_pass (client->parser) == 0) if (connection_check_admin_pass (client->parser) == 0)
{ {
client_send_401 (client, NULL); client_send_401 (client, NULL);

View File

@ -209,7 +209,7 @@ ogg_codec_t *initial_kate_page (format_plugin_t *plugin, ogg_page *page)
} }
#else #else
/* we don't have libkate, so we examine the packet magic by hand */ /* we don't have libkate, so we examine the packet magic by hand */
if ((packet.bytes<9) || memcmp(packet.packet, "\x80kate\0\0\0\0", 9)) if ((packet.bytes<8) || memcmp(packet.packet, "\x80kate\0\0\0", 8))
{ {
ogg_stream_clear (&codec->os); ogg_stream_clear (&codec->os);
free (kate_codec); free (kate_codec);

View File

@ -124,12 +124,6 @@ static refbuf_t *process_theora_page (ogg_state_t *ogg_info, ogg_codec_t *codec,
refbuf = make_refbuf_with_page (codec, page); refbuf = make_refbuf_with_page (codec, page);
/* DEBUG3 ("refbuf %p has pageno %ld, %llu", refbuf, ogg_page_pageno (page), (uint64_t)granulepos); */ /* DEBUG3 ("refbuf %p has pageno %ld, %llu", refbuf, ogg_page_pageno (page), (uint64_t)granulepos); */
if (has_keyframe && codec->possible_start)
{
codec->possible_start->sync_point = 1;
refbuf_release (codec->possible_start);
codec->possible_start = NULL;
}
if (granulepos != theora->prev_granulepos || granulepos == 0) if (granulepos != theora->prev_granulepos || granulepos == 0)
{ {
if (codec->possible_start) if (codec->possible_start)
@ -138,6 +132,12 @@ static refbuf_t *process_theora_page (ogg_state_t *ogg_info, ogg_codec_t *codec,
codec->possible_start = refbuf; codec->possible_start = refbuf;
} }
theora->prev_granulepos = granulepos; theora->prev_granulepos = granulepos;
if (has_keyframe && codec->possible_start)
{
codec->possible_start->sync_point = 1;
refbuf_release (codec->possible_start);
codec->possible_start = NULL;
}
return refbuf; return refbuf;
} }

View File

@ -31,6 +31,8 @@
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/socket.h> #include <sys/socket.h>
#define SCN_OFF_T SCNdMAX
#define PRI_OFF_T PRIdMAX
#else #else
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
@ -546,7 +548,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
{ {
ret = 0; ret = 0;
if (strncasecmp (range, "bytes=", 6) == 0) if (strncasecmp (range, "bytes=", 6) == 0)
ret = sscanf (range+6, "%" SCNdMAX "-", &rangenumber); ret = sscanf (range+6, "%" SCN_OFF_T "-", &rangenumber);
if (ret == 1 && rangenumber>=0 && rangenumber < content_length) if (ret == 1 && rangenumber>=0 && rangenumber < content_length)
{ {
@ -576,10 +578,10 @@ int fserve_client_create (client_t *httpclient, const char *path)
"HTTP/1.1 206 Partial Content\r\n" "HTTP/1.1 206 Partial Content\r\n"
"Date: %s\r\n" "Date: %s\r\n"
"Accept-Ranges: bytes\r\n" "Accept-Ranges: bytes\r\n"
"Content-Length: %" PRIdMAX "\r\n" "Content-Length: %" PRI_OFF_T "\r\n"
"Content-Range: bytes %" PRIdMAX "Content-Range: bytes %" PRI_OFF_T
"-%" PRIdMAX "-%" PRI_OFF_T
"/%" PRIdMAX "\r\n" "/%" PRI_OFF_T "\r\n"
"Content-Type: %s\r\n\r\n", "Content-Type: %s\r\n\r\n",
currenttime, currenttime,
new_content_len, new_content_len,
@ -607,7 +609,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
"HTTP/1.0 200 OK\r\n" "HTTP/1.0 200 OK\r\n"
"Accept-Ranges: bytes\r\n" "Accept-Ranges: bytes\r\n"
"Content-Type: %s\r\n" "Content-Type: %s\r\n"
"Content-Length: %" PRIdMAX "\r\n" "Content-Length: %" PRI_OFF_T "\r\n"
"\r\n", "\r\n",
type, type,
content_length); content_length);

View File

@ -504,6 +504,7 @@ static void *start_relay_stream (void *arg)
thread_mutex_unlock (&src->lock); thread_mutex_unlock (&src->lock);
/* cleanup relay, but prevent this relay from starting up again too soon */ /* cleanup relay, but prevent this relay from starting up again too soon */
relay->source->on_demand = 0;
relay->start = global.time + relay->interval; relay->start = global.time + relay->interval;
relay->cleanup = 1; relay->cleanup = 1;
@ -1094,6 +1095,7 @@ static void *_slave_thread(void *arg)
} }
/* trigger any YP processing */ /* trigger any YP processing */
yp_thread_startup(); yp_thread_startup();
stats_global_calc();
} }
connection_thread_shutdown(); connection_thread_shutdown();
INFO0 ("shutting down current relays"); INFO0 ("shutting down current relays");

View File

@ -44,7 +44,8 @@
#if !defined HAVE_ATOLL && defined HAVE_STRTOLL #if !defined HAVE_ATOLL && defined HAVE_STRTOLL
#define atoll(nptr) strtoll(nptr, (char **)NULL, 10) #define atoll(nptr) strtoll(nptr, (char **)NULL, 10)
#endif #endif
static void stats_global_calc (void);
#define VAL_BUFSIZE 20
#define STATS_EVENT_SET 0 #define STATS_EVENT_SET 0
#define STATS_EVENT_INC 1 #define STATS_EVENT_INC 1
@ -54,6 +55,31 @@ static void stats_global_calc (void);
#define STATS_EVENT_REMOVE 5 #define STATS_EVENT_REMOVE 5
#define STATS_EVENT_HIDDEN 6 #define STATS_EVENT_HIDDEN 6
typedef struct _stats_node_tag
{
char *name;
char *value;
int hidden;
} stats_node_t;
typedef struct _stats_event_tag
{
char *source;
char *name;
char *value;
int hidden;
int action;
struct _stats_event_tag *next;
} stats_event_t;
typedef struct _stats_source_tag
{
char *source;
int hidden;
avl_tree *stats_tree;
} stats_source_t;
typedef struct _event_queue_tag typedef struct _event_queue_tag
{ {
volatile stats_event_t *head; volatile stats_event_t *head;
@ -73,19 +99,14 @@ typedef struct _event_listener_tag
} event_listener_t; } event_listener_t;
static volatile int _stats_running = 0; static volatile int _stats_running = 0;
static thread_type *_stats_thread_id;
static volatile int _stats_threads = 0; static volatile int _stats_threads = 0;
static stats_t _stats; static stats_t _stats;
static mutex_t _stats_mutex; static mutex_t _stats_mutex;
static event_queue_t _global_event_queue;
spin_t _global_event_mutex;
static volatile event_listener_t *_event_listeners; static volatile event_listener_t *_event_listeners;
static void *_stats_thread(void *arg);
static int _compare_stats(void *a, void *b, void *arg); static int _compare_stats(void *a, void *b, void *arg);
static int _compare_source_stats(void *a, void *b, void *arg); static int _compare_source_stats(void *a, void *b, void *arg);
static int _free_stats(void *key); static int _free_stats(void *key);
@ -95,34 +116,21 @@ static stats_node_t *_find_node(avl_tree *tree, const char *name);
static stats_source_t *_find_source(avl_tree *tree, const char *source); static stats_source_t *_find_source(avl_tree *tree, const char *source);
static void _free_event(stats_event_t *event); static void _free_event(stats_event_t *event);
static stats_event_t *_get_event_from_queue (event_queue_t *queue); static stats_event_t *_get_event_from_queue (event_queue_t *queue);
static void process_event (stats_event_t *event);
/* simple helper function for creating an event */ /* simple helper function for creating an event */
static stats_event_t *build_event (const char *source, const char *name, const char *value) static void build_event (stats_event_t *event, const char *source, const char *name, const char *value)
{ {
stats_event_t *event; event->source = (char *)source;
event->name = (char *)name;
event = (stats_event_t *)calloc(1, sizeof(stats_event_t)); event->value = (char *)value;
if (event)
{
if (source)
event->source = (char *)strdup(source);
if (name)
event->name = (char *)strdup(name);
if (value) if (value)
event->value = (char *)strdup(value); event->action = 0;
else else
event->action = STATS_EVENT_REMOVE; event->action = STATS_EVENT_REMOVE;
} }
return event;
}
static void queue_global_event (stats_event_t *event)
{
thread_spin_lock(&_global_event_mutex);
_add_event_to_queue (event, &_global_event_queue);
thread_spin_unlock(&_global_event_mutex);
}
void stats_initialize(void) void stats_initialize(void)
{ {
@ -135,13 +143,26 @@ void stats_initialize(void)
/* set up global mutex */ /* set up global mutex */
thread_mutex_create("stats", &_stats_mutex); thread_mutex_create("stats", &_stats_mutex);
/* set up stats queues */
event_queue_init (&_global_event_queue);
thread_spin_create("stats_global_event", &_global_event_mutex);
/* fire off the stats thread */ /* fire off the stats thread */
_stats_running = 1; _stats_running = 1;
_stats_thread_id = thread_create("Stats Thread", _stats_thread, NULL, THREAD_ATTACHED);
stats_event_time (NULL, "server_start");
/* global currently active stats */
stats_event (NULL, "clients", "0");
stats_event (NULL, "connections", "0");
stats_event (NULL, "sources", "0");
stats_event (NULL, "stats", "0");
stats_event (NULL, "listeners", "0");
/* global accumulating stats */
stats_event (NULL, "client_connections", "0");
stats_event (NULL, "source_client_connections", "0");
stats_event (NULL, "source_relay_connections", "0");
stats_event (NULL, "source_total_connections", "0");
stats_event (NULL, "stats_connections", "0");
stats_event (NULL, "listener_connections", "0");
stats_event (NULL, "outgoing_kbitrate", "0");
} }
void stats_shutdown(void) void stats_shutdown(void)
@ -153,7 +174,6 @@ void stats_shutdown(void)
/* wait for thread to exit */ /* wait for thread to exit */
_stats_running = 0; _stats_running = 0;
thread_join(_stats_thread_id);
/* wait for other threads to shut down */ /* wait for other threads to shut down */
do { do {
@ -166,25 +186,9 @@ void stats_shutdown(void)
/* free the queues */ /* free the queues */
/* destroy the queue mutexes */
thread_spin_destroy(&_global_event_mutex);
thread_mutex_destroy(&_stats_mutex); thread_mutex_destroy(&_stats_mutex);
avl_tree_free(_stats.source_tree, _free_source_stats); avl_tree_free(_stats.source_tree, _free_source_stats);
avl_tree_free(_stats.global_tree, _free_stats); avl_tree_free(_stats.global_tree, _free_stats);
while (1)
{
stats_event_t *event = _get_event_from_queue (&_global_event_queue);
if (event == NULL) break;
if(event->source)
free(event->source);
if(event->value)
free(event->value);
if(event->name)
free(event->name);
free(event);
}
} }
stats_t *stats_get_stats(void) stats_t *stats_get_stats(void)
@ -203,16 +207,15 @@ stats_t *stats_get_stats(void)
/* simple name=tag stat create/update */ /* simple name=tag stat create/update */
void stats_event(const char *source, const char *name, const char *value) void stats_event(const char *source, const char *name, const char *value)
{ {
stats_event_t *event; stats_event_t event;
if (value && xmlCheckUTF8 ((unsigned char *)value) == 0) if (value && xmlCheckUTF8 ((unsigned char *)value) == 0)
{ {
WARN2 ("seen non-UTF8 data, probably incorrect metadata (%s, %s)", name, value); WARN2 ("seen non-UTF8 data, probably incorrect metadata (%s, %s)", name, value);
return; return;
} }
event = build_event (source, name, value); build_event (&event, source, name, (char *)value);
if (event) process_event (&event);
queue_global_event (event);
} }
@ -258,17 +261,14 @@ void stats_event_conv(const char *mount, const char *name, const char *value, co
* source stats tree. */ * source stats tree. */
void stats_event_hidden (const char *source, const char *name, int hidden) void stats_event_hidden (const char *source, const char *name, int hidden)
{ {
stats_event_t *event;
const char *str = NULL; const char *str = NULL;
stats_event_t event;
if (hidden) if (hidden)
str = ""; str = "";
event = build_event (source, name, str); build_event (&event, source, name, NULL);
if (event) event.action = STATS_EVENT_HIDDEN;
{ process_event (&event);
event->action = STATS_EVENT_HIDDEN;
queue_global_event (event);
}
} }
/* printf style formatting for stat create/update */ /* printf style formatting for stat create/update */
@ -325,51 +325,46 @@ char *stats_get_value(const char *source, const char *name)
/* increase the value in the provided stat by 1 */ /* increase the value in the provided stat by 1 */
void stats_event_inc(const char *source, const char *name) void stats_event_inc(const char *source, const char *name)
{ {
stats_event_t *event = build_event (source, name, NULL); stats_event_t event;
char buffer[VAL_BUFSIZE];
build_event (&event, source, name, buffer);
/* DEBUG2("%s on %s", name, source==NULL?"global":source); */ /* DEBUG2("%s on %s", name, source==NULL?"global":source); */
if (event) event.action = STATS_EVENT_INC;
{ process_event (&event);
event->action = STATS_EVENT_INC;
queue_global_event (event);
}
} }
void stats_event_add(const char *source, const char *name, unsigned long value) void stats_event_add(const char *source, const char *name, unsigned long value)
{ {
stats_event_t *event = build_event (source, name, NULL); stats_event_t event;
char buffer [VAL_BUFSIZE];
build_event (&event, source, name, buffer);
snprintf (buffer, VAL_BUFSIZE, "%ld", value);
event.action = STATS_EVENT_ADD;
/* DEBUG2("%s on %s", name, source==NULL?"global":source); */ /* DEBUG2("%s on %s", name, source==NULL?"global":source); */
if (event) process_event (&event);
{
event->value = malloc (16);
snprintf (event->value, 16, "%ld", value);
event->action = STATS_EVENT_ADD;
queue_global_event (event);
}
} }
void stats_event_sub(const char *source, const char *name, unsigned long value) void stats_event_sub(const char *source, const char *name, unsigned long value)
{ {
stats_event_t *event = build_event (source, name, NULL); stats_event_t event;
char buffer[VAL_BUFSIZE];
build_event (&event, source, name, buffer);
/* DEBUG2("%s on %s", name, source==NULL?"global":source); */ /* DEBUG2("%s on %s", name, source==NULL?"global":source); */
if (event) snprintf (buffer, VAL_BUFSIZE, "%ld", value);
{ event.action = STATS_EVENT_SUB;
event->value = malloc (16); process_event (&event);
snprintf (event->value, 16, "%ld", value);
event->action = STATS_EVENT_SUB;
queue_global_event (event);
}
} }
/* decrease the value in the provided stat by 1 */ /* decrease the value in the provided stat by 1 */
void stats_event_dec(const char *source, const char *name) void stats_event_dec(const char *source, const char *name)
{ {
stats_event_t event;
char buffer[VAL_BUFSIZE];
/* DEBUG2("%s on %s", name, source==NULL?"global":source); */ /* DEBUG2("%s on %s", name, source==NULL?"global":source); */
stats_event_t *event = build_event (source, name, NULL); build_event (&event, source, name, buffer);
if (event) event.action = STATS_EVENT_DEC;
{ process_event (&event);
event->action = STATS_EVENT_DEC;
queue_global_event (event);
}
} }
/* note: you must call this function only when you have exclusive access /* note: you must call this function only when you have exclusive access
@ -448,8 +443,8 @@ static stats_event_t *_copy_event(stats_event_t *event)
/* helper to apply specialised changes to a stats node */ /* helper to apply specialised changes to a stats node */
static void modify_node_event (stats_node_t *node, stats_event_t *event) static void modify_node_event (stats_node_t *node, stats_event_t *event)
{ {
char *str; if (node == NULL || event == NULL)
return;
if (event->action == STATS_EVENT_HIDDEN) if (event->action == STATS_EVENT_HIDDEN)
{ {
if (event->value) if (event->value)
@ -479,15 +474,10 @@ static void modify_node_event (stats_node_t *node, stats_event_t *event)
default: default:
break; break;
} }
str = malloc (20); snprintf (event->value, VAL_BUFSIZE, "%" PRId64, value);
snprintf (str, 20, "%" PRId64, value);
free (event->value);
event->value = strdup (str);
} }
else
str = (char *)strdup (event->value);
free (node->value); free (node->value);
node->value = str; node->value = strdup (event->value);
} }
@ -604,7 +594,7 @@ void stats_event_time (const char *mount, const char *name)
char buffer[100]; char buffer[100];
localtime_r (&now, &local); localtime_r (&now, &local);
strftime (buffer, sizeof (buffer), "%a, %d %b %Y %H:%M:%S %z", &local); strftime (buffer, sizeof (buffer), ICECAST_TIME_FMT, &local);
stats_event (mount, name, buffer); stats_event (mount, name, buffer);
} }
@ -640,43 +630,8 @@ void stats_global (ice_config_t *config)
stats_event (NULL, "admin", config->admin); stats_event (NULL, "admin", config->admin);
} }
static void process_event_unlocked (stats_event_t *event)
static void *_stats_thread(void *arg)
{ {
stats_event_t *event;
stats_event_time (NULL, "server_start");
/* global currently active stats */
stats_event (NULL, "clients", "0");
stats_event (NULL, "connections", "0");
stats_event (NULL, "sources", "0");
stats_event (NULL, "stats", "0");
stats_event (NULL, "listeners", "0");
/* global accumulating stats */
stats_event (NULL, "client_connections", "0");
stats_event (NULL, "source_client_connections", "0");
stats_event (NULL, "source_relay_connections", "0");
stats_event (NULL, "source_total_connections", "0");
stats_event (NULL, "stats_connections", "0");
stats_event (NULL, "listener_connections", "0");
stats_event (NULL, "outgoing_kbitrate", "0");
INFO0 ("stats thread started");
while (_stats_running) {
if (_global_event_queue.head != NULL) {
/* grab the next event from the queue */
thread_spin_lock(&_global_event_mutex);
event = _get_event_from_queue (&_global_event_queue);
thread_spin_unlock(&_global_event_mutex);
if (event == NULL)
continue;
event->next = NULL;
thread_mutex_lock(&_stats_mutex);
/* check if we are dealing with a global or source event */ /* check if we are dealing with a global or source event */
if (event->source == NULL) if (event->source == NULL)
process_global_event (event); process_global_event (event);
@ -686,18 +641,15 @@ static void *_stats_thread(void *arg)
/* now we have an event that's been processed into the running stats */ /* now we have an event that's been processed into the running stats */
/* this event should get copied to event listeners' queues */ /* this event should get copied to event listeners' queues */
stats_listener_send (event); stats_listener_send (event);
}
/* now we need to destroy the event */ static void process_event (stats_event_t *event)
_free_event(event); {
if (event == NULL)
return;
thread_mutex_lock (&_stats_mutex);
process_event_unlocked (event);
thread_mutex_unlock (&_stats_mutex); thread_mutex_unlock (&_stats_mutex);
continue;
}
thread_sleep(500000);
stats_global_calc();
}
return NULL;
} }
/* you must have the _stats_mutex locked here */ /* you must have the _stats_mutex locked here */
@ -705,6 +657,9 @@ static void _unregister_listener(event_listener_t *listener)
{ {
event_listener_t **prev = (event_listener_t **)&_event_listeners, event_listener_t **prev = (event_listener_t **)&_event_listeners,
*current = *prev; *current = *prev;
stats_event_t stats_count, *event;
char buffer [VAL_BUFSIZE];
while (current) while (current)
{ {
if (current == listener) if (current == listener)
@ -715,6 +670,15 @@ static void _unregister_listener(event_listener_t *listener)
prev = &current->next; prev = &current->next;
current = *prev; current = *prev;
} }
/* remove this listener before sending this change */
build_event (&stats_count, NULL, "stats_connections", buffer);
stats_count.action = STATS_EVENT_DEC;
process_event_unlocked (&stats_count);
/* flush any extra that sneaked on at the last moment */
while ((event = _get_event_from_queue (&listener->queue)) != NULL)
_free_event (event);
} }
@ -823,8 +787,12 @@ static void _register_listener (event_listener_t *listener)
avl_node *node2; avl_node *node2;
stats_event_t *event; stats_event_t *event;
stats_source_t *source; stats_source_t *source;
stats_event_t stats_count;
char buffer[20];
thread_mutex_lock(&_stats_mutex); build_event (&stats_count, NULL, "stats_connections", buffer);
stats_count.action = STATS_EVENT_INC;
process_event_unlocked (&stats_count);
/* first we fill our queue with the current stats */ /* first we fill our queue with the current stats */
@ -855,11 +823,8 @@ static void _register_listener (event_listener_t *listener)
/* now we register to receive future event notices */ /* now we register to receive future event notices */
listener->next = (event_listener_t *)_event_listeners; listener->next = (event_listener_t *)_event_listeners;
_event_listeners = listener; _event_listeners = listener;
thread_mutex_unlock(&_stats_mutex);
} }
static void check_uri (event_listener_t *listener, client_t *client) static void check_uri (event_listener_t *listener, client_t *client)
{ {
const char *mount = httpp_getvar (client->parser, HTTPP_VAR_URI); const char *mount = httpp_getvar (client->parser, HTTPP_VAR_URI);
@ -883,12 +848,10 @@ void *stats_connection(void *arg)
/* increment the thread count */ /* increment the thread count */
thread_mutex_lock(&_stats_mutex); thread_mutex_lock(&_stats_mutex);
_stats_threads++; _stats_threads++;
stats_event_args (NULL, "stats", "%d", _stats_threads);
thread_mutex_unlock(&_stats_mutex);
thread_mutex_create("stats local event", &listener.mutex); thread_mutex_create("stats local event", &listener.mutex);
_register_listener (&listener); _register_listener (&listener);
thread_mutex_unlock(&_stats_mutex);
while (_stats_running) { while (_stats_running) {
thread_mutex_lock (&listener.mutex); thread_mutex_lock (&listener.mutex);
@ -908,7 +871,6 @@ void *stats_connection(void *arg)
thread_mutex_lock(&_stats_mutex); thread_mutex_lock(&_stats_mutex);
_unregister_listener (&listener); _unregister_listener (&listener);
_stats_threads--; _stats_threads--;
stats_event_args (NULL, "stats", "%d", _stats_threads);
thread_mutex_unlock(&_stats_mutex); thread_mutex_unlock(&_stats_mutex);
thread_mutex_destroy (&listener.mutex); thread_mutex_destroy (&listener.mutex);
@ -939,7 +901,7 @@ typedef struct _source_xml_tag {
struct _source_xml_tag *next; struct _source_xml_tag *next;
} source_xml_t; } source_xml_t;
static xmlNodePtr _find_xml_node(char *mount, source_xml_t **list, xmlNodePtr root) static xmlNodePtr _find_xml_node(const char *mount, source_xml_t **list, xmlNodePtr root)
{ {
source_xml_t *node, *node2; source_xml_t *node, *node2;
int found = 0; int found = 0;
@ -1185,30 +1147,21 @@ void stats_clear_virtual_mounts (void)
} }
static void stats_global_calc (void) void stats_global_calc (void)
{ {
stats_event_t event; stats_event_t event;
stats_node_t *node; char buffer [VAL_BUFSIZE];
char buffer [20];
static time_t next_update = 0; static time_t next_update = 0;
if (global.time < next_update) if (global.time < next_update)
return; return;
next_update = global.time + 1; next_update = global.time + 1;
event.source = NULL; build_event (&event, NULL, "outgoing_kbitrate", buffer);
event.name = "outgoing_kbitrate";
event.value = buffer;
event.action = STATS_EVENT_SET;
thread_mutex_lock (&_stats_mutex); thread_mutex_lock (&_stats_mutex);
node = _find_node(_stats.global_tree, event.name);
if (node)
{
snprintf (buffer, sizeof(buffer), "%" PRIu64, snprintf (buffer, sizeof(buffer), "%" PRIu64,
(int64_t)(global_getrate_avg (global.out_bitrate) * 8 / 1000.0 + 0.5)); (int64_t)(global_getrate_avg (global.out_bitrate) * 8 / 1000.0 + 0.5));
modify_node_event (node, &event); process_event_unlocked (&event);
stats_listener_send (&event);
}
thread_mutex_unlock (&_stats_mutex); thread_mutex_unlock (&_stats_mutex);
} }

View File

@ -22,31 +22,6 @@
#include <libxml/tree.h> #include <libxml/tree.h>
typedef struct _stats_node_tag
{
char *name;
char *value;
int hidden;
} stats_node_t;
typedef struct _stats_event_tag
{
char *source;
char *name;
char *value;
int hidden;
int action;
struct _stats_event_tag *next;
} stats_event_t;
typedef struct _stats_source_tag
{
char *source;
int hidden;
avl_tree *stats_tree;
} stats_source_t;
typedef struct _stats_tag typedef struct _stats_tag
{ {
avl_tree *global_tree; avl_tree *global_tree;
@ -93,6 +68,7 @@ void stats_event_time (const char *mount, const char *name);
void *stats_connection(void *arg); void *stats_connection(void *arg);
void stats_callback (client_t *client, void *notused); void stats_callback (client_t *client, void *notused);
void stats_global_calc(void);
void stats_transform_xslt(client_t *client, const char *uri); void stats_transform_xslt(client_t *client, const char *uri);
void stats_sendxml(client_t *client); void stats_sendxml(client_t *client);

12
web/admin.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<link rel="stylesheet" type="text/css" href="/style.css" />
<title>Icecast Streaming Media Server</title>
</head>
<frameset rows="170,*" border="0">
<frame name="header" frameborder="0" scrolling="no" width="100%" src="/adminbar.html" />
<frame name="content" frameborder="0" scrolling="auto" width="100%" src="/admin/stats.xsl" />
</frameset>
</html>

View File

@ -12,5 +12,5 @@ EXTRA_DIST = ConfigTab.cpp ConfigTab.h Icecast2win.clw Icecast2win.cpp \
colors.h icecast.dsp icecast.ico icecast2.iss icecast2logo2.bmp\ colors.h icecast.dsp icecast.ico icecast2.iss icecast2logo2.bmp\
resource.h running.bmp stopped.bmp TRAYNOT.h Traynot.cpp \ resource.h running.bmp stopped.bmp TRAYNOT.h Traynot.cpp \
icecast2_console.dsw icecast2_console.dsp credits.bmp icecast2title.bmp \ icecast2_console.dsw icecast2_console.dsp credits.bmp icecast2title.bmp \
icecastService.cpp icecastService.dsp fnmatch.h icecastService.cpp icecastService.dsp

View File

@ -3,7 +3,7 @@
[Setup] [Setup]
AppName=Icecast2-KH AppName=Icecast2-KH
AppVerName=Icecast v2.3.1-kh34 AppVerName=Icecast v2.3.2-kh1
AppPublisherURL=http://www.icecast.org AppPublisherURL=http://www.icecast.org
AppSupportURL=http://www.icecast.org AppSupportURL=http://www.icecast.org
AppUpdatesURL=http://www.icecast.org AppUpdatesURL=http://www.icecast.org
@ -13,7 +13,7 @@ AllowNoIcons=yes
LicenseFile=..\COPYING LicenseFile=..\COPYING
InfoAfterFile=..\README InfoAfterFile=..\README
OutputDir=. OutputDir=.
OutputBaseFilename=icecast2_win32_v2.3.1-kh34_setup OutputBaseFilename=icecast2_win32_v2.3.2-kh1_setup
WizardImageFile=icecast2logo2.bmp WizardImageFile=icecast2logo2.bmp
WizardImageStretch=no WizardImageStretch=no
; uncomment the following line if you want your installation to run on NT 3.51 too. ; uncomment the following line if you want your installation to run on NT 3.51 too.

View File

@ -50,7 +50,8 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 theora_static_d.lib libspeex.lib ogg_static.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libcurl.lib vorbis_static.lib libxml2.lib libxslt.lib iconv.lib pthreadVSE.lib ws2_32.lib ssleay32MT.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"libcd.lib" /nodefaultlib:"libcmt.lib" # ADD LINK32 theora_static_d.lib libspeex.lib ogg_static.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libcurl.lib vorbis_static.lib libxml2.lib libxslt.lib iconv.lib pthreadVSE.lib ws2_32.lib winmm.lib ssleay32MT.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"libcd.lib" /nodefaultlib:"libcmt.lib"
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "icecast2 console - Win32 Debug" !ELSEIF "$(CFG)" == "icecast2 console - Win32 Debug"
@ -74,7 +75,8 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 theora_static_d.lib libspeex.lib ogg_static.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libcurl.lib vorbis_static.lib libxml2.lib libxslt.lib iconv.lib pthreadVSE.lib ws2_32.lib ssleay32MT.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /nodefaultlib:"libcmt.lib" /nodefaultlib:"libcmtd.lib" /pdbtype:sept # ADD LINK32 theora_static_d.lib libspeex.lib ogg_static.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libcurl.lib vorbis_static.lib libxml2.lib libxslt.lib iconv.lib pthreadVSE.lib ws2_32.lib winmm.lib ssleay32MT.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /nodefaultlib:"libcmt.lib" /nodefaultlib:"libcmtd.lib" /pdbtype:sept
# SUBTRACT LINK32 /pdb:none
!ENDIF !ENDIF

View File

@ -43,7 +43,6 @@ RSC=rc.exe
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I ".." /I "..\src" /D "NDEBUG" /D "_CONSOLE" /D "WIN32_SERVICE" /D HAVE_CONFIG_H=1 /D "WIN32" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I ".." /I "..\src" /D "NDEBUG" /D "_CONSOLE" /D "WIN32_SERVICE" /D HAVE_CONFIG_H=1 /D "WIN32" /D "_MBCS" /YX /FD /c
# SUBTRACT CPP /Z<none>
# ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -51,8 +50,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 libspeex.lib theora_static_d.lib ogg_static.lib vorbis_static.lib pthreadVSE.lib ssleay32MT.lib libcurl.lib libxml2.lib libxslt.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /machine:I386 /nodefaultlib:"libcmt.lib" /nodefaultlib:"libcmtd.lib" /nodefaultlib:"libcd.lib" # ADD LINK32 libspeex.lib theora_static_d.lib ogg_static.lib vorbis_static.lib pthreadVSE.lib ssleay32MT.lib libcurl.lib libxml2.lib libxslt.lib ws2_32.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /machine:I386 /nodefaultlib:"libcmt.lib" /nodefaultlib:"libcmtd.lib" /nodefaultlib:"libcd.lib"
# SUBTRACT LINK32 /debug
!ELSEIF "$(CFG)" == "icecastService - Win32 Debug" !ELSEIF "$(CFG)" == "icecastService - Win32 Debug"
@ -76,8 +74,8 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 vorbis_static.lib iconv.lib libspeex.lib theora_static_d.lib ogg_static_d.lib vorbis_static_d.lib pthreadVSE.lib ssleay32MT.lib libcurl.lib libxml2.lib libxslt.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"libcmt.lib" /out:"service_debug/icecast2service.exe" /pdbtype:sept # ADD LINK32 vorbis_static.lib iconv.lib libspeex.lib theora_static_d.lib ogg_static_d.lib vorbis_static_d.lib pthreadVSE.lib ssleay32MT.lib libcurl.lib libxml2.lib libxslt.lib ws2_32.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"libcmt.lib" /out:"service_debug/icecast2service.exe" /pdbtype:sept
# SUBTRACT LINK32 /verbose # SUBTRACT LINK32 /pdb:none
!ENDIF !ENDIF