1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-09-29 04:25:55 -04:00

bump to kh17. fix failing relay crash case. fix flashpolcy crash case.

fix memory corruption case when moving clients between workers.
some minor timing changes


svn path=/icecast/branches/kh/icecast/; revision=16632
This commit is contained in:
Karl Heyes 2009-10-11 01:20:04 +00:00
parent de49138869
commit 9a7a36acc4
12 changed files with 82 additions and 55 deletions

7
NEWS
View File

@ -16,6 +16,13 @@ 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-kh17
. fix possible memory corruption when using multiple workers
. a few minor timing changes, nothing major.
. fix possible race case in multiple file handle close
. kh16b. fix possible crash case with relay failing
. kh16a. some fserve changes exposed a crash bug with flash clients.
2.3.2-kh16 2.3.2-kh16
. you can now fallback to file if the initial mountpont is not available as long . you can now fallback to file if the initial mountpont is not available as long
as there is a limit-rate set at some point within the fallback chain. as there is a limit-rate set at some point within the fallback chain.

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.2-kh16" #define VERSION "2.3.2-kh17"
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION VERSION #define PACKAGE_VERSION VERSION

View File

@ -1,4 +1,4 @@
AC_INIT([Icecast], [2.3.2-kh16], [karl@xiph.org]) AC_INIT([Icecast], [2.3.2-kh17], [karl@xiph.org])
AC_PREREQ(2.59) AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(src/main.c) AC_CONFIG_SRCDIR(src/main.c)

View File

@ -317,29 +317,37 @@ worker_t *find_least_busy_handler (void)
} }
void client_change_worker (client_t *client, worker_t *dest_worker) static void worker_add_client (worker_t *worker, client_t *client)
{
*worker->last_p = client;
worker->last_p = &client->next_on_worker;
client->worker = worker;
++worker->count;
if (worker->wakeup_ms - worker->time_ms > 15)
thread_cond_signal (&worker->cond); /* wake thread if required */
}
int client_change_worker (client_t *client, worker_t *dest_worker)
{ {
worker_t *this_worker = client->worker; worker_t *this_worker = client->worker;
if (dest_worker->running == 0)
return 0;
// make sure this client list is ok // make sure this client list is ok
*this_worker->current_p = client->next_on_worker; *this_worker->current_p = client->next_on_worker;
if (client->next_on_worker == NULL)
this_worker->last_p = this_worker->current_p;
this_worker->count--; this_worker->count--;
thread_mutex_unlock (&this_worker->lock); thread_mutex_unlock (&this_worker->lock);
client->next_on_worker = NULL; client->next_on_worker = NULL;
thread_mutex_lock (&dest_worker->lock); thread_mutex_lock (&dest_worker->lock);
if (dest_worker->running) worker_add_client (dest_worker, client);
{
client->worker = dest_worker;
*dest_worker->last_p = client;
dest_worker->last_p = &client->next_on_worker;
dest_worker->count++;
client->flags |= CLIENT_HAS_CHANGED_THREAD;
// make client inactive so that the destination thread does not run it straight away
client->flags &= ~CLIENT_ACTIVE;
}
thread_mutex_unlock (&dest_worker->lock); thread_mutex_unlock (&dest_worker->lock);
thread_mutex_lock (&this_worker->lock); thread_mutex_lock (&this_worker->lock);
return 1;
} }
@ -354,12 +362,7 @@ void client_add_worker (client_t *client)
thread_rwlock_unlock (&workers_lock); thread_rwlock_unlock (&workers_lock);
client->schedule_ms = handler->time_ms; client->schedule_ms = handler->time_ms;
*handler->last_p = client; worker_add_client (handler, client);
handler->last_p = &client->next_on_worker;
client->worker = handler;
++handler->count;
if (handler->wakeup_ms - handler->time_ms > 15)
thread_cond_signal (&handler->cond); /* wake thread if required */
thread_mutex_unlock (&handler->lock); thread_mutex_unlock (&handler->lock);
} }
@ -406,13 +409,9 @@ void *worker (void *arg)
ret = client->ops->process (client); ret = client->ops->process (client);
/* special handler, client has moved away to another worker */ /* special handler, client has moved away to another worker */
if (client->flags & CLIENT_HAS_CHANGED_THREAD) if (ret > 0)
{ {
client->flags &= ~CLIENT_HAS_CHANGED_THREAD;
client->flags |= CLIENT_ACTIVE;
client = *prevp; client = *prevp;
if (client == NULL)
handler->last_p = prevp;
continue; continue;
} }
if (ret < 0) if (ret < 0)

View File

@ -131,7 +131,7 @@ int client_send_bytes (client_t *client, const void *buf, unsigned len);
int client_read_bytes (client_t *client, void *buf, unsigned len); int client_read_bytes (client_t *client, void *buf, unsigned len);
void client_set_queue (client_t *client, refbuf_t *refbuf); void client_set_queue (client_t *client, refbuf_t *refbuf);
void client_change_worker (client_t *client, worker_t *dest_worker); int client_change_worker (client_t *client, worker_t *dest_worker);
void client_add_worker (client_t *client); void client_add_worker (client_t *client);
worker_t *find_least_busy_handler (void); worker_t *find_least_busy_handler (void);
void workers_adjust (int new_count); void workers_adjust (int new_count);
@ -141,7 +141,7 @@ void workers_adjust (int new_count);
#define CLIENT_ACTIVE (001) #define CLIENT_ACTIVE (001)
#define CLIENT_AUTHENTICATED (002) #define CLIENT_AUTHENTICATED (002)
#define CLIENT_IS_SLAVE (004) #define CLIENT_IS_SLAVE (004)
#define CLIENT_HAS_CHANGED_THREAD (010)
#define CLIENT_NO_CONTENT_LENGTH (020) #define CLIENT_NO_CONTENT_LENGTH (020)
#define CLIENT_HAS_INTRO_CONTENT (040) #define CLIENT_HAS_INTRO_CONTENT (040)
#define CLIENT_FORMAT_BIT (01000) #define CLIENT_FORMAT_BIT (01000)

View File

@ -704,6 +704,7 @@ static int http_client_request (client_t *client)
fb.flags = FS_NORMAL|FS_USE_ADMIN; fb.flags = FS_NORMAL|FS_USE_ADMIN;
fb.fallback = NULL; fb.fallback = NULL;
fb.limit = 0; fb.limit = 0;
client->respcode = 200;
refbuf_release (refbuf); refbuf_release (refbuf);
client->shared_data = NULL; client->shared_data = NULL;
client->check_buffer = format_generic_write_to_client; client->check_buffer = format_generic_write_to_client;

View File

@ -66,11 +66,20 @@ void format_plugin_clear (format_plugin_t *format)
if (format == NULL) if (format == NULL)
return; return;
rate_free (format->in_bitrate); rate_free (format->in_bitrate);
format->in_bitrate = NULL;
rate_free (format->out_bitrate); rate_free (format->out_bitrate);
format->out_bitrate = NULL;
free (format->charset); free (format->charset);
format->charset = NULL; format->charset = NULL;
if (format->free_plugin) if (format->free_plugin)
format->free_plugin (format); 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;
} }

View File

@ -188,6 +188,7 @@ static int _compare_fh(void *arg, void *a, void *b)
static int _delete_fh (void *mapping) static int _delete_fh (void *mapping)
{ {
fh_node *fh = mapping; fh_node *fh = mapping;
fh->refcount--;
if (fh->refcount) if (fh->refcount)
WARN2 ("handle for %s has refcount %d", fh->finfo.mount, fh->refcount); WARN2 ("handle for %s has refcount %d", fh->finfo.mount, fh->refcount);
else else
@ -242,6 +243,7 @@ static fh_node *open_fh (fbinfo *finfo, client_t *client)
{ {
free (fh); free (fh);
thread_mutex_lock (&result->lock); thread_mutex_lock (&result->lock);
avl_tree_unlock (fh_cache);
result->refcount++; result->refcount++;
if (client) if (client)
{ {
@ -259,7 +261,6 @@ static fh_node *open_fh (fbinfo *finfo, client_t *client)
} }
} }
DEBUG2 ("refcount now %d for %s", result->refcount, result->finfo.mount); DEBUG2 ("refcount now %d for %s", result->refcount, result->finfo.mount);
avl_tree_unlock (fh_cache);
return result; return result;
} }
@ -578,11 +579,11 @@ int fserve_client_create (client_t *httpclient, const char *path)
// fh must be locked before calling this // fh must be locked before calling this
static void fh_release (fh_node *fh) static void fh_release (fh_node *fh)
{ {
fh->refcount--;
if (fh->finfo.mount[0]) if (fh->finfo.mount[0])
DEBUG2 ("refcount now %d on %s", fh->refcount, fh->finfo.mount); DEBUG2 ("refcount now %d on %s", fh->refcount, fh->finfo.mount);
if (fh->refcount) if (fh->refcount > 1)
{ {
fh->refcount--;
thread_mutex_unlock (&fh->lock); thread_mutex_unlock (&fh->lock);
return; return;
} }
@ -592,7 +593,7 @@ static void fh_release (fh_node *fh)
thread_mutex_unlock (&fh->lock); thread_mutex_unlock (&fh->lock);
avl_tree_wlock (fh_cache); avl_tree_wlock (fh_cache);
thread_mutex_lock (&fh->lock); thread_mutex_lock (&fh->lock);
if (fh->refcount) if (fh->refcount > 1)
thread_mutex_unlock (&fh->lock); thread_mutex_unlock (&fh->lock);
else else
avl_delete (fh_cache, fh, _delete_fh); avl_delete (fh_cache, fh, _delete_fh);
@ -732,7 +733,7 @@ static int prefile_send (client_t *client)
if (written > 30000) if (written > 30000)
break; break;
} }
client->schedule_ms = client->worker->time_ms + 150; client->schedule_ms = client->worker->time_ms + 100;
return 0; return 0;
} }

View File

@ -1259,8 +1259,7 @@ static int relay_read (client_t *client)
source->flags &= ~SOURCE_RUNNING; source->flags &= ~SOURCE_RUNNING;
if (relay->on_demand && source->listeners == 0) if (relay->on_demand && source->listeners == 0)
source->flags &= ~SOURCE_RUNNING; source->flags &= ~SOURCE_RUNNING;
source_read (source); return source_read (source);
return 0;
} }
if (relay->running && relay->enable) if (relay->running && relay->enable)
{ {

View File

@ -72,8 +72,8 @@ static int send_to_listener (client_t *client);
static int http_source_listener (client_t *client); static int http_source_listener (client_t *client);
static int http_source_intro (client_t *client); static int http_source_intro (client_t *client);
static int locate_start_on_queue (source_t *source, client_t *client); static int locate_start_on_queue (source_t *source, client_t *client);
static void listener_change_worker (client_t *client, source_t *source); static int listener_change_worker (client_t *client, source_t *source);
static void source_change_worker (source_t *source); static int source_change_worker (source_t *source);
static int source_client_callback (client_t *client); static int source_client_callback (client_t *client);
#ifdef _WIN32 #ifdef _WIN32
@ -412,7 +412,7 @@ static void update_source_stats (source_t *source)
* and sent back, however NULL is also valid as in the case of a short * and sent back, however NULL is also valid as in the case of a short
* timeout and there's no data pending. * timeout and there's no data pending.
*/ */
void source_read (source_t *source) int source_read (source_t *source)
{ {
client_t *client = source->client; client_t *client = source->client;
refbuf_t *refbuf = NULL; refbuf_t *refbuf = NULL;
@ -445,11 +445,10 @@ void source_read (source_t *source)
} }
if (current >= source->client_stats_update) if (current >= source->client_stats_update)
{ {
source_change_worker (source);
update_source_stats (source); update_source_stats (source);
source->client_stats_update = current + source->stats_interval; source->client_stats_update = current + source->stats_interval;
thread_mutex_unlock (&source->lock); if (source_change_worker (source))
return; return 1;
} }
if (source->limit_rate) if (source->limit_rate)
{ {
@ -486,6 +485,8 @@ void source_read (source_t *source)
source->skip_duration = 30; source->skip_duration = 30;
else else
source->skip_duration = (long)(source->skip_duration * 1.8); source->skip_duration = (long)(source->skip_duration * 1.8);
if (source->skip_duration > 700)
source->skip_duration = 700;
break; break;
} }
source->skip_duration = (long)(source->skip_duration * 0.9); source->skip_duration = (long)(source->skip_duration * 0.9);
@ -570,6 +571,7 @@ void source_read (source_t *source)
if (skip) if (skip)
client->schedule_ms = client->worker->time_ms + source->skip_duration; client->schedule_ms = client->worker->time_ms + source->skip_duration;
thread_mutex_unlock (&source->lock); thread_mutex_unlock (&source->lock);
return 0;
} }
@ -585,7 +587,7 @@ static int source_client_read (client_t *client)
INFO1 ("streaming duration expired on %s", source->mount); INFO1 ("streaming duration expired on %s", source->mount);
} }
if (source_running (source)) if (source_running (source))
source_read (source); return source_read (source);
else else
{ {
if ((source->flags & SOURCE_TERMINATING) == 0) if ((source->flags & SOURCE_TERMINATING) == 0)
@ -845,7 +847,8 @@ static int send_to_listener (client_t *client)
// do we migrate this listener to the same handler as the source client // do we migrate this listener to the same handler as the source client
if (source->client && source->client->worker != client->worker) if (source->client && source->client->worker != client->worker)
listener_change_worker (client, source); if (listener_change_worker (client, source))
return 1;
client->schedule_ms = client->worker->time_ms; client->schedule_ms = client->worker->time_ms;
while (loop) while (loop)
@ -867,12 +870,12 @@ static int send_to_listener (client_t *client)
if (bytes < 0) if (bytes < 0)
break; /* can't write any more */ break; /* can't write any more */
client->schedule_ms += 100; client->schedule_ms += 40;
total_written += bytes; total_written += bytes;
loop--; loop--;
} }
if (loop == 0) if (loop == 0)
client->schedule_ms -= 500; client->schedule_ms -= 190;
rate_add (source->format->out_bitrate, total_written, client->worker->time_ms); rate_add (source->format->out_bitrate, total_written, client->worker->time_ms);
global_add_bitrates (global.out_bitrate, total_written, client->worker->time_ms); global_add_bitrates (global.out_bitrate, total_written, client->worker->time_ms);
source->bytes_sent_since_update += total_written; source->bytes_sent_since_update += total_written;
@ -1852,10 +1855,11 @@ int source_startup (client_t *client, const char *uri)
/* check to see if the source client can be moved to a less busy worker thread. /* check to see if the source client can be moved to a less busy worker thread.
* we only move the source client, not the listeners, they will move later * we only move the source client, not the listeners, they will move later
*/ */
void source_change_worker (source_t *source) int source_change_worker (source_t *source)
{ {
client_t *client = source->client; client_t *client = source->client;
worker_t *this_worker = client->worker, *worker; worker_t *this_worker = client->worker, *worker;
int ret = 0;
thread_rwlock_rlock (&workers_lock); thread_rwlock_rlock (&workers_lock);
worker = find_least_busy_handler (); worker = find_least_busy_handler ();
@ -1864,22 +1868,26 @@ void source_change_worker (source_t *source)
if (worker->count + source->listeners + 10 < client->worker->count) if (worker->count + source->listeners + 10 < client->worker->count)
{ {
thread_mutex_unlock (&source->lock); thread_mutex_unlock (&source->lock);
client_change_worker (client, worker); ret = client_change_worker (client, worker);
DEBUG2 ("moving source from %p to %p", this_worker, worker); if (ret)
thread_mutex_lock (&source->lock); DEBUG2 ("moving source from %p to %p", this_worker, worker);
else
thread_mutex_lock (&source->lock);
} }
} }
thread_rwlock_unlock (&workers_lock); thread_rwlock_unlock (&workers_lock);
return ret;
} }
/* move listener client to worker theread that the source is on. This will /* move listener client to worker theread that the source is on. This will
* help cache but prevent overloading a single worker with many listeners. * help cache but prevent overloading a single worker with many listeners.
*/ */
void listener_change_worker (client_t *client, source_t *source) int listener_change_worker (client_t *client, source_t *source)
{ {
worker_t *this_worker = client->worker, *dest_worker; worker_t *this_worker = client->worker, *dest_worker;
long diff; long diff;
int ret = 0;
thread_rwlock_rlock (&workers_lock); thread_rwlock_rlock (&workers_lock);
dest_worker = source->client->worker; dest_worker = source->client->worker;
@ -1888,10 +1896,13 @@ void listener_change_worker (client_t *client, source_t *source)
if (diff < 1000 && this_worker != dest_worker) if (diff < 1000 && this_worker != dest_worker)
{ {
thread_mutex_unlock (&source->lock); thread_mutex_unlock (&source->lock);
client_change_worker (client, dest_worker); ret = client_change_worker (client, dest_worker);
DEBUG2 ("moving listener from %p to %p", this_worker, dest_worker); if (ret)
thread_mutex_lock (&source->lock); DEBUG2 ("moving listener from %p to %p", this_worker, dest_worker);
else
thread_mutex_lock (&source->lock);
} }
thread_rwlock_unlock (&workers_lock); thread_rwlock_unlock (&workers_lock);
return ret;
} }

View File

@ -106,7 +106,7 @@ void source_listener_detach (client_t *client);
void source_main(source_t *source); void source_main(source_t *source);
void source_recheck_mounts (int update_all); void source_recheck_mounts (int update_all);
int source_add_listener (const char *mount, mount_proxy *mountinfo, client_t *client); int source_add_listener (const char *mount, mount_proxy *mountinfo, client_t *client);
void source_read (source_t *source); int source_read (source_t *source);
void source_setup_listener (source_t *source, client_t *client); void source_setup_listener (source_t *source, client_t *client);
void source_init (source_t *source); void source_init (source_t *source);
void source_shutdown (source_t *source, int with_fallback); void source_shutdown (source_t *source, int with_fallback);

View File

@ -3,7 +3,7 @@
[Setup] [Setup]
AppName=Icecast2-KH AppName=Icecast2-KH
AppVerName=Icecast v2.3.2-kh16 AppVerName=Icecast v2.3.2-kh17
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,10 +13,10 @@ AllowNoIcons=yes
LicenseFile=..\COPYING LicenseFile=..\COPYING
InfoAfterFile=..\README InfoAfterFile=..\README
OutputDir=. OutputDir=.
OutputBaseFilename=icecast2_win32_v2.3.2-kh16_setup OutputBaseFilename=icecast2_win32_v2.3.2-kh17_setup
WizardImageFile=icecast2logo2.bmp WizardImageFile=icecast2logo2.bmp
WizardImageStretch=no WizardImageStretch=no
VersionInfoProductVersion=kh16 VersionInfoProductVersion=kh17
VersionInfoVersion=2.3.2 VersionInfoVersion=2.3.2
; 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.
; MinVersion=4,3.51 ; MinVersion=4,3.51