[xiph-commits] r16933 - in icecast/branches/kh/icecast: . src win32
karl at svn.xiph.org
karl at svn.xiph.org
Sun Feb 21 19:47:07 PST 2010
Author: karl
Date: 2010-02-21 19:47:07 -0800 (Sun, 21 Feb 2010)
New Revision: 16933
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_htpasswd.c
icecast/branches/kh/icecast/src/client.c
icecast/branches/kh/icecast/src/client.h
icecast/branches/kh/icecast/src/format.c
icecast/branches/kh/icecast/src/format_mp3.c
icecast/branches/kh/icecast/src/fserve.c
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/util.c
icecast/branches/kh/icecast/win32/Icecast2win.dsp
icecast/branches/kh/icecast/win32/icecast2.iss
Log:
kh21. mostly fixes.
. fix worker stalled bug if source exits and new listener connects. A deadlock
on the source tree is possible.
. a few small changes to locking scope.
. NULL pointer fix with a stopped relay without a fallback but with listeners
still on it
. make fh_node use a tree for quick lookup. This is not like the sources.
. a few other smaller fixes and consistency checks implemented.
. 2 patches from moo, fixes #1646, #1648. still need to assess a third but is
not critical.
Modified: icecast/branches/kh/icecast/NEWS
===================================================================
--- icecast/branches/kh/icecast/NEWS 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/NEWS 2010-02-22 03:47:07 UTC (rev 16933)
@@ -16,6 +16,19 @@
any extra tags are show in the conf/icecast.xml.dist file
+2.3.2-kh21
+. Fix possible stall bug when a source exits and when adding a listener, only
+ keep the source_tree lock held until a source lock can be acquired.
+. tighten up where the certain locks are held/released.
+. win32 stat return code fix
+. added a few internal checks and some log messages.
+. fixes from moo, #1646, status response header first always, #1648, return ICY
+ response for mpc
+. make fh_node use tree for quick lookup
+. zero out format structure, remove previous stats for restarting relays
+. NULL pointer fix in cases where a relay was being cleared of listeners without
+ a fallback mount, eg being disabled or removed from slave list or reread XML
+
2.3.2-kh20
. fix possible lock imbalance bug if mutliple workers set
. make sure listeners are not paused if relay is not running
Modified: icecast/branches/kh/icecast/config.h.vc6
===================================================================
--- icecast/branches/kh/icecast/config.h.vc6 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/config.h.vc6 2010-02-22 03:47:07 UTC (rev 16933)
@@ -95,7 +95,7 @@
#define PACKAGE_NAME "Icecast"
/* Version number of package */
-#define VERSION "2.3.2-kh20"
+#define VERSION "2.3.2-kh21"
/* 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-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/configure.in 2010-02-22 03:47:07 UTC (rev 16933)
@@ -1,4 +1,4 @@
-AC_INIT([Icecast], [2.3.2-kh20], [karl at xiph.org])
+AC_INIT([Icecast], [2.3.2-kh21], [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-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/admin.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -1137,11 +1137,13 @@
if (strcmp (action, "viewxml") == 0)
{
xmlDocPtr doc;
+ char *mount = strdup (source->mount);
DEBUG0("Got shoutcast viewxml request");
- doc = stats_get_xml (STATS_ALL, source->mount);
thread_mutex_unlock (&source->lock);
+ doc = stats_get_xml (STATS_ALL, mount);
admin_send_response (doc, client, XSLT, "viewxml.xsl");
xmlFreeDoc(doc);
+ free (mount);
return;
}
thread_mutex_unlock (&source->lock);
Modified: icecast/branches/kh/icecast/src/auth.c
===================================================================
--- icecast/branches/kh/icecast/src/auth.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/auth.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -372,7 +372,7 @@
int move_listener (client_t *client, struct _fbinfo *finfo)
{
- source_t *source;
+ source_t *source, *prev;
DEBUG1 ("moving listener to %s", finfo->mount);
avl_tree_rlock (global.source_tree);
@@ -388,16 +388,17 @@
thread_mutex_unlock (&source->lock);
return 0;
}
- if (source->fallback.mount)
- {
- source_t *prev = source;
+ prev = source;
+ if (prev->fallback.mount)
source = source_find_mount (prev->fallback.mount);
- thread_mutex_unlock (&prev->lock);
- }
+ else
+ source = NULL;
+ thread_mutex_unlock (&prev->lock);
}
avl_tree_unlock (global.source_tree);
if (client->flags & CLIENT_IS_SLAVE)
return -1;
+ DEBUG1 ("no source, trying %s as a file", finfo->mount);
return fserve_setup_client_fb (client, finfo);
}
@@ -440,9 +441,7 @@
return 0;
}
- avl_tree_rlock (global.source_tree);
ret = source_add_listener (mount, mountinfo, client);
- avl_tree_unlock (global.source_tree);
if (ret == -2)
{
@@ -514,7 +513,6 @@
DEBUG1 ("on mountpoint %s", mount);
source_startup (client, mount);
}
- client->flags |= CLIENT_ACTIVE;
}
Modified: icecast/branches/kh/icecast/src/auth_htpasswd.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_htpasswd.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/auth_htpasswd.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -110,7 +110,7 @@
if (htpasswd->filename == NULL)
return;
- if (stat (htpasswd->filename, &file_stat) < 0)
+ if (stat (htpasswd->filename, &file_stat) != 0)
{
WARN1 ("failed to check status of %s", htpasswd->filename);
@@ -186,18 +186,20 @@
if (client->username && client->password)
break;
- free (client->username);
val = httpp_get_query_param (client->parser, "user");
if (val)
{
+ free (client->username);
client->username = strdup (val);
val = httpp_get_query_param (client->parser, "pass");
if (val)
{
+ free (client->password);
client->password = strdup (val);
break;
}
}
+ DEBUG0 ("No username/password provided by client");
return AUTH_FAILED;
} while (0);
@@ -210,14 +212,15 @@
htpasswd_user *found = result;
char *hashed_pw;
- thread_rwlock_unlock (&htpasswd->file_rwlock);
hashed_pw = get_hash (client->password, strlen (client->password));
if (strcmp (found->pass, hashed_pw) == 0)
{
free (hashed_pw);
+ thread_rwlock_unlock (&htpasswd->file_rwlock);
client->flags |= CLIENT_AUTHENTICATED;
return AUTH_OK;
}
+ thread_rwlock_unlock (&htpasswd->file_rwlock);
free (hashed_pw);
DEBUG0 ("incorrect password for client");
return AUTH_FAILED;
Modified: icecast/branches/kh/icecast/src/client.c
===================================================================
--- icecast/branches/kh/icecast/src/client.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/client.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -119,6 +119,17 @@
}
+int client_compare (void *compare_arg, void *a, void *b)
+{
+ client_t *ca = a, *cb = b;
+
+ if (ca->connection.id < cb->connection.id) return -1;
+ if (ca->connection.id > cb->connection.id) return 1;
+
+ return 0;
+}
+
+
/* helper function for reading data from a client */
int client_read_bytes (client_t *client, void *buf, unsigned len)
{
Modified: icecast/branches/kh/icecast/src/client.h
===================================================================
--- icecast/branches/kh/icecast/src/client.h 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/client.h 2010-02-22 03:47:07 UTC (rev 16933)
@@ -113,8 +113,6 @@
/* functions to process client */
struct _client_functions *ops;
-
- client_t *next; /* for use with grouping similar clients */
};
client_t *client_create (sock_t sock);
@@ -130,6 +128,7 @@
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);
+int client_compare (void *compare_arg, void *a, void *b);
int client_change_worker (client_t *client, worker_t *dest_worker);
void client_add_worker (client_t *client);
Modified: icecast/branches/kh/icecast/src/format.c
===================================================================
--- icecast/branches/kh/icecast/src/format.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/format.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -65,21 +65,12 @@
{
if (format == NULL)
return;
+ if (format->free_plugin)
+ format->free_plugin (format);
rate_free (format->in_bitrate);
- format->in_bitrate = NULL;
rate_free (format->out_bitrate);
- format->out_bitrate = NULL;
free (format->charset);
- format->charset = NULL;
- if (format->free_plugin)
- format->free_plugin (format);
- format->get_buffer = NULL;
- format->write_buf_to_client = NULL;
- format->write_buf_to_file = NULL;
- format->create_client_data = NULL;
- format->free_plugin = NULL;
- format->set_tag = NULL;
- format->apply_settings = NULL;
+ memset (format, 0, sizeof (format_plugin_t));
}
@@ -172,8 +163,12 @@
if (client->respcode == 0)
{
- bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"
- "content-type: %s\r\n", plugin->contenttype);
+ const char *useragent = httpp_getvar (client->parser, "user-agent");
+ const char *protocol = "HTTP/1.0";
+ if (useragent && strstr(useragent, "shoutcastsource")) /* hack for mpc */
+ protocol = "ICY";
+ bytes = snprintf (ptr, remaining, "%s 200 OK\r\n"
+ "content-type: %s\r\n", protocol, plugin->contenttype);
remaining -= bytes;
ptr += bytes;
client->respcode = 200;
Modified: icecast/branches/kh/icecast/src/format_mp3.c
===================================================================
--- icecast/branches/kh/icecast/src/format_mp3.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/format_mp3.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -693,14 +693,25 @@
mp3_client_data *client_mp3 = calloc(1,sizeof(mp3_client_data));
mp3_state *source_mp3 = plugin->_state;
const char *metadata;
- size_t remaining = 4096;
- char *ptr = client->refbuf->data;
+ size_t remaining;
+ char *ptr;
int bytes;
const char *useragent;
if (client_mp3 == NULL)
return -1;
+ client->format_data = client_mp3;
+ client->free_client_data = free_mp3_client_data;
+ client->refbuf->len = 0;
+
+ if (format_general_headers (plugin, client) < 0)
+ return -1;
+
+ client->refbuf->len -= 2;
+ remaining = 4096 - client->refbuf->len;
+ ptr = client->refbuf->data + client->refbuf->len;
+
/* hack for flash player, it wants a length. It has also been reported that the useragent
* appears as MSIE if run in internet explorer */
useragent = httpp_getvar (client->parser, "user-agent");
@@ -716,16 +727,6 @@
ptr += bytes;
}
- client->format_data = client_mp3;
- client->free_client_data = free_mp3_client_data;
- client->refbuf->len = 4096 - remaining;
-
- if (format_general_headers (plugin, client) < 0)
- return -1;
-
- remaining = 4096 - client->refbuf->len + 2;
- ptr = client->refbuf->data + client->refbuf->len - 2;
-
/* check for shoutcast style metadata inserts */
metadata = httpp_getvar(client->parser, "icy-metadata");
if (metadata && atoi(metadata))
Modified: icecast/branches/kh/icecast/src/fserve.c
===================================================================
--- icecast/branches/kh/icecast/src/fserve.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/fserve.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -78,7 +78,7 @@
FILE *fp;
time_t stats_update;
format_plugin_t *format;
- client_t *clients;
+ avl_tree *clients;
} fh_node;
int fserve_running;
@@ -204,6 +204,7 @@
format_plugin_clear (fh->format);
free (fh->format);
}
+ avl_tree_free (fh->clients, NULL);
free (fh->finfo.mount);
free (fh->finfo.fallback);
free (fh);
@@ -214,18 +215,7 @@
static void remove_from_fh (fh_node *fh, client_t *client)
{
- client_t **p = &fh->clients;
- while (*p)
- {
- if (*p == client)
- {
- *p = client->next;
- return;
- }
- p = &(*p)->next;
- }
- if (fh->finfo.mount)
- DEBUG0 ("unable to find client");
+ avl_delete (fh->clients, client, NULL);
}
@@ -249,8 +239,7 @@
{
if (finfo->mount && (finfo->flags & FS_FALLBACK))
stats_event_args (result->finfo.mount, "listeners", "%ld", result->refcount);
- client->next = result->clients;
- result->clients = client;
+ avl_insert (result->clients, client);
if (result->format)
{
if (result->format->create_client_data && client->format_data == NULL)
@@ -314,13 +303,13 @@
}
thread_mutex_create (&fh->lock);
thread_mutex_lock (&fh->lock);
+ fh->clients = avl_tree_new (client_compare, NULL);
fh->refcount = 1;
if (client)
{
if (finfo->mount && (finfo->flags & FS_FALLBACK))
stats_event_flags (fh->finfo.mount, "listeners", "1", STATS_HIDDEN);
- fh->clients = client;
- client->next = NULL;
+ avl_insert (fh->clients, client);
}
fh->finfo.mount = strdup (finfo->mount);
if (finfo->fallback)
@@ -1058,10 +1047,11 @@
fh_node *fh = open_fh (&finfo, NULL);
if (fh)
{
- client_t *listener = fh->clients;
+ avl_node *node = avl_get_first (fh->clients);
- while (listener)
+ while (node)
{
+ client_t *listener = (client_t *)node->key;
if (listener->connection.id == id)
{
listener->connection.error = 1;
@@ -1069,7 +1059,7 @@
v = "1";
break;
}
- listener = listener->next;
+ node = avl_get_next (node);
}
fh_release (fh);
break;
@@ -1115,10 +1105,12 @@
fh_node *fh = open_fh (&finfo, NULL);
if (fh)
{
- client_t *listener = fh->clients;
+ avl_node *node = avl_get_first (fh->clients);
- while (listener)
+ while (node)
{
+ client_t *listener = (client_t *)node->key;
+
if (show_listeners)
{
xmlNodePtr node = xmlNewChild (srcnode, NULL, XMLSTR("listener"), NULL);
@@ -1147,7 +1139,7 @@
}
entries++;
- listener = listener->next;
+ node = avl_get_next (node);
}
fh_release (fh);
}
Modified: icecast/branches/kh/icecast/src/slave.c
===================================================================
--- icecast/branches/kh/icecast/src/slave.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/slave.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -1231,11 +1231,12 @@
int fallback = 1;
if (relay->running && relay->enable && client->connection.con_time)
fallback = 0;
+ /* don't pause listeners if relay shutting down */
+ if (relay->running == 0 || relay->enable == 0)
+ source->flags &= ~SOURCE_PAUSE_LISTENERS;
// fallback listeners unless relay is to be retried
source_shutdown (source, fallback);
source->flags |= SOURCE_TERMINATING;
- if (relay->running == 0) /* don't pause listeners if relay shutting down */
- source->flags &= ~SOURCE_PAUSE_LISTENERS;
}
if (source->termination_count && source->termination_count <= source->listeners)
{
Modified: icecast/branches/kh/icecast/src/source.c
===================================================================
--- icecast/branches/kh/icecast/src/source.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/source.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -115,17 +115,6 @@
};
-static int compare_listeners (void *compare_arg, void *a, void *b)
-{
- client_t *ca = a, *cb = b;
-
- if (ca->connection.id < cb->connection.id) return -1;
- if (ca->connection.id > cb->connection.id) return 1;
-
- return 0;
-}
-
-
/* Allocate a new source with the stated mountpoint, if one already
* exists with that mountpoint in the global source tree then return
* NULL.
@@ -152,7 +141,7 @@
src->mount = strdup (mount);
src->listener_send_trigger = 10000;
src->format = calloc (1, sizeof(format_plugin_t));
- src->clients = avl_tree_new (compare_listeners, NULL);
+ src->clients = avl_tree_new (client_compare, NULL);
thread_mutex_create (&src->lock);
@@ -281,6 +270,7 @@
break;
}
config_release_config ();
+ DEBUG1 ("no listeners are attached to %s", source->mount);
if (i)
stats_event_sub (NULL, "listeners", i);
source->listeners = 0;
@@ -353,7 +343,6 @@
static int _free_source (void *p)
{
source_t *source = p;
- source_clear_listeners (source);
source_clear_source (source);
/* make sure all YP entries have gone */
@@ -364,7 +353,6 @@
WARN1("active listeners on mountpoint %s", source->mount);
avl_tree_free (source->clients, NULL);
- thread_mutex_unlock (&source->lock);
thread_mutex_destroy (&source->lock);
INFO1 ("freeing source \"%s\"", source->mount);
@@ -378,8 +366,9 @@
/* Remove the provided source from the global tree and free it */
void source_free_source (source_t *source)
{
+ INFO1 ("source %s to be freed", source->mount);
avl_tree_wlock (global.source_tree);
- thread_mutex_lock (&source->lock); /* listeners may of been added */
+ INFO1 ("removing source %s from tree", source->mount);
avl_delete (global.source_tree, source, _free_source);
avl_tree_unlock (global.source_tree);
}
@@ -1272,7 +1261,7 @@
if (mountinfo && mountinfo->type)
stats_event (source->mount, "server_type", mountinfo->type);
else
- if (source->format)
+ if (source->format && source->format->contenttype)
stats_event (source->mount, "server_type", source->format->contenttype);
if (mountinfo && mountinfo->subtype)
@@ -1609,12 +1598,15 @@
global_reduce_bitrate_sampling (global.out_bitrate);
thread_mutex_lock (&source->lock);
+ source->flags &= ~(SOURCE_RUNNING|SOURCE_ON_DEMAND);
/* log bytes read in access log */
if (source->format)
client->connection.sent_bytes = source->format->read_bytes;
- thread_mutex_unlock (&source->lock);
client_destroy (client);
+ source_clear_listeners (source);
+ thread_mutex_unlock (&source->lock);
+
source_free_source (source);
thread_rwlock_unlock (&global.shutdown_lock);
slave_update_all_mounts();
@@ -1660,13 +1652,14 @@
do
{
- source = source_find_mount_raw (mount);
if (loop == 0)
{
WARN0 ("preventing a fallback loop");
client_send_403 (client, "Fallback through too many mountpoints");
return -1;
}
+ avl_tree_rlock (global.source_tree);
+ source = source_find_mount_raw (mount);
if (source)
{
thread_mutex_lock (&source->lock);
@@ -1674,6 +1667,7 @@
break;
thread_mutex_unlock (&source->lock);
}
+ avl_tree_unlock (global.source_tree);
if (minfo && minfo->limit_rate)
bitrate = minfo->limit_rate;
if (minfo == NULL || minfo->fallback_mount == NULL)
@@ -1701,6 +1695,8 @@
} while (1);
/* ok, we found a source and it is locked */
+ avl_tree_unlock (global.source_tree);
+
if (client->flags & CLIENT_IS_SLAVE)
{
if (source->client == NULL && (source->flags & SOURCE_ON_DEMAND) == 0)
@@ -1848,17 +1844,17 @@
if (source)
{
ice_config_t *config = config_get_config();
+ int source_limit = config->source_limit;
+ config_release_config();
global_lock();
- if (global.sources >= config->source_limit)
+ if (global.sources >= source_limit)
{
- config_release_config();
WARN1 ("Request to add source when maximum source limit reached %d", global.sources);
global_unlock();
client_send_403 (client, "too many streams connected");
source_free_source (source);
return 0;
}
- config_release_config();
global.sources++;
INFO1 ("sources count is now %d", global.sources);
stats_event_args (NULL, "sources", "%d", global.sources);
@@ -1895,6 +1891,7 @@
client->ops = &source_client_http_ops;
thread_mutex_unlock (&source->lock);
}
+ client->flags |= CLIENT_ACTIVE;
}
else
{
Modified: icecast/branches/kh/icecast/src/stats.c
===================================================================
--- icecast/branches/kh/icecast/src/stats.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/stats.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -1012,7 +1012,11 @@
source = source_find_mount_raw (show_mount);
if (source)
+ {
+ thread_mutex_lock (&source->lock);
admin_source_listeners (source, node);
+ thread_mutex_unlock (&source->lock);
+ }
avl_tree_unlock (global.source_tree);
}
Modified: icecast/branches/kh/icecast/src/util.c
===================================================================
--- icecast/branches/kh/icecast/src/util.c 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/src/util.c 2010-02-22 03:47:07 UTC (rev 16933)
@@ -721,7 +721,10 @@
while (count && node->index <= cutoff)
{
struct rate_calc_node *to_go = node;
- node = calc->current->next = node->next;
+ if (node == NULL || node->next == NULL)
+ abort();
+ node = node->next;
+ calc->current->next = node;
calc->total -= to_go->value;
free (to_go);
count--;
Modified: icecast/branches/kh/icecast/win32/Icecast2win.dsp
===================================================================
--- icecast/branches/kh/icecast/win32/Icecast2win.dsp 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/win32/Icecast2win.dsp 2010-02-22 03:47:07 UTC (rev 16933)
@@ -109,7 +109,7 @@
# End Source File
# Begin Source File
-SOURCE=\xiph\icecast\branches\kh\icecast\src\main.c
+SOURCE=..\src\main.c
# End Source File
# Begin Source File
Modified: icecast/branches/kh/icecast/win32/icecast2.iss
===================================================================
--- icecast/branches/kh/icecast/win32/icecast2.iss 2010-02-22 00:12:03 UTC (rev 16932)
+++ icecast/branches/kh/icecast/win32/icecast2.iss 2010-02-22 03:47:07 UTC (rev 16933)
@@ -3,7 +3,7 @@
[Setup]
AppName=Icecast2-KH
-AppVerName=Icecast v2.3.2-kh20
+AppVerName=Icecast v2.3.2-kh21
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-kh20_setup
+OutputBaseFilename=icecast2_win32_v2.3.2-kh21_setup
WizardImageFile=icecast2logo2.bmp
WizardImageStretch=no
VersionInfoVersion=2.3.2
@@ -69,6 +69,3 @@
Filename: "{app}\icecastService.exe"; Parameters: "remove"
-
-
-
More information about the commits
mailing list