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:
parent
de49138869
commit
9a7a36acc4
7
NEWS
7
NEWS
@ -16,6 +16,13 @@ Feature differences from SVN trunk
|
||||
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
|
||||
. 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.
|
||||
|
@ -95,7 +95,7 @@
|
||||
#define PACKAGE_NAME "Icecast"
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.3.2-kh16"
|
||||
#define VERSION "2.3.2-kh17"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION VERSION
|
||||
|
@ -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_CONFIG_SRCDIR(src/main.c)
|
||||
|
43
src/client.c
43
src/client.c
@ -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;
|
||||
|
||||
if (dest_worker->running == 0)
|
||||
return 0;
|
||||
// make sure this client list is ok
|
||||
*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--;
|
||||
thread_mutex_unlock (&this_worker->lock);
|
||||
client->next_on_worker = NULL;
|
||||
|
||||
thread_mutex_lock (&dest_worker->lock);
|
||||
if (dest_worker->running)
|
||||
{
|
||||
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;
|
||||
}
|
||||
worker_add_client (dest_worker, client);
|
||||
|
||||
thread_mutex_unlock (&dest_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);
|
||||
|
||||
client->schedule_ms = handler->time_ms;
|
||||
*handler->last_p = 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 */
|
||||
worker_add_client (handler, client);
|
||||
thread_mutex_unlock (&handler->lock);
|
||||
}
|
||||
|
||||
@ -406,13 +409,9 @@ void *worker (void *arg)
|
||||
ret = client->ops->process (client);
|
||||
|
||||
/* 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;
|
||||
if (client == NULL)
|
||||
handler->last_p = prevp;
|
||||
continue;
|
||||
}
|
||||
if (ret < 0)
|
||||
|
@ -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);
|
||||
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);
|
||||
worker_t *find_least_busy_handler (void);
|
||||
void workers_adjust (int new_count);
|
||||
@ -141,7 +141,7 @@ void workers_adjust (int new_count);
|
||||
#define CLIENT_ACTIVE (001)
|
||||
#define CLIENT_AUTHENTICATED (002)
|
||||
#define CLIENT_IS_SLAVE (004)
|
||||
#define CLIENT_HAS_CHANGED_THREAD (010)
|
||||
|
||||
#define CLIENT_NO_CONTENT_LENGTH (020)
|
||||
#define CLIENT_HAS_INTRO_CONTENT (040)
|
||||
#define CLIENT_FORMAT_BIT (01000)
|
||||
|
@ -704,6 +704,7 @@ static int http_client_request (client_t *client)
|
||||
fb.flags = FS_NORMAL|FS_USE_ADMIN;
|
||||
fb.fallback = NULL;
|
||||
fb.limit = 0;
|
||||
client->respcode = 200;
|
||||
refbuf_release (refbuf);
|
||||
client->shared_data = NULL;
|
||||
client->check_buffer = format_generic_write_to_client;
|
||||
|
@ -66,11 +66,20 @@ void format_plugin_clear (format_plugin_t *format)
|
||||
if (format == NULL)
|
||||
return;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
11
src/fserve.c
11
src/fserve.c
@ -188,6 +188,7 @@ static int _compare_fh(void *arg, void *a, void *b)
|
||||
static int _delete_fh (void *mapping)
|
||||
{
|
||||
fh_node *fh = mapping;
|
||||
fh->refcount--;
|
||||
if (fh->refcount)
|
||||
WARN2 ("handle for %s has refcount %d", fh->finfo.mount, fh->refcount);
|
||||
else
|
||||
@ -242,6 +243,7 @@ static fh_node *open_fh (fbinfo *finfo, client_t *client)
|
||||
{
|
||||
free (fh);
|
||||
thread_mutex_lock (&result->lock);
|
||||
avl_tree_unlock (fh_cache);
|
||||
result->refcount++;
|
||||
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);
|
||||
avl_tree_unlock (fh_cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -578,11 +579,11 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
||||
// fh must be locked before calling this
|
||||
static void fh_release (fh_node *fh)
|
||||
{
|
||||
fh->refcount--;
|
||||
if (fh->finfo.mount[0])
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -592,7 +593,7 @@ static void fh_release (fh_node *fh)
|
||||
thread_mutex_unlock (&fh->lock);
|
||||
avl_tree_wlock (fh_cache);
|
||||
thread_mutex_lock (&fh->lock);
|
||||
if (fh->refcount)
|
||||
if (fh->refcount > 1)
|
||||
thread_mutex_unlock (&fh->lock);
|
||||
else
|
||||
avl_delete (fh_cache, fh, _delete_fh);
|
||||
@ -732,7 +733,7 @@ static int prefile_send (client_t *client)
|
||||
if (written > 30000)
|
||||
break;
|
||||
}
|
||||
client->schedule_ms = client->worker->time_ms + 150;
|
||||
client->schedule_ms = client->worker->time_ms + 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1259,8 +1259,7 @@ static int relay_read (client_t *client)
|
||||
source->flags &= ~SOURCE_RUNNING;
|
||||
if (relay->on_demand && source->listeners == 0)
|
||||
source->flags &= ~SOURCE_RUNNING;
|
||||
source_read (source);
|
||||
return 0;
|
||||
return source_read (source);
|
||||
}
|
||||
if (relay->running && relay->enable)
|
||||
{
|
||||
|
39
src/source.c
39
src/source.c
@ -72,8 +72,8 @@ static int send_to_listener (client_t *client);
|
||||
static int http_source_listener (client_t *client);
|
||||
static int http_source_intro (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 void source_change_worker (source_t *source);
|
||||
static int listener_change_worker (client_t *client, source_t *source);
|
||||
static int source_change_worker (source_t *source);
|
||||
static int source_client_callback (client_t *client);
|
||||
|
||||
#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
|
||||
* timeout and there's no data pending.
|
||||
*/
|
||||
void source_read (source_t *source)
|
||||
int source_read (source_t *source)
|
||||
{
|
||||
client_t *client = source->client;
|
||||
refbuf_t *refbuf = NULL;
|
||||
@ -445,11 +445,10 @@ void source_read (source_t *source)
|
||||
}
|
||||
if (current >= source->client_stats_update)
|
||||
{
|
||||
source_change_worker (source);
|
||||
update_source_stats (source);
|
||||
source->client_stats_update = current + source->stats_interval;
|
||||
thread_mutex_unlock (&source->lock);
|
||||
return;
|
||||
if (source_change_worker (source))
|
||||
return 1;
|
||||
}
|
||||
if (source->limit_rate)
|
||||
{
|
||||
@ -486,6 +485,8 @@ void source_read (source_t *source)
|
||||
source->skip_duration = 30;
|
||||
else
|
||||
source->skip_duration = (long)(source->skip_duration * 1.8);
|
||||
if (source->skip_duration > 700)
|
||||
source->skip_duration = 700;
|
||||
break;
|
||||
}
|
||||
source->skip_duration = (long)(source->skip_duration * 0.9);
|
||||
@ -570,6 +571,7 @@ void source_read (source_t *source)
|
||||
if (skip)
|
||||
client->schedule_ms = client->worker->time_ms + source->skip_duration;
|
||||
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);
|
||||
}
|
||||
if (source_running (source))
|
||||
source_read (source);
|
||||
return source_read (source);
|
||||
else
|
||||
{
|
||||
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
|
||||
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;
|
||||
while (loop)
|
||||
@ -867,12 +870,12 @@ static int send_to_listener (client_t *client)
|
||||
if (bytes < 0)
|
||||
break; /* can't write any more */
|
||||
|
||||
client->schedule_ms += 100;
|
||||
client->schedule_ms += 40;
|
||||
total_written += bytes;
|
||||
loop--;
|
||||
}
|
||||
if (loop == 0)
|
||||
client->schedule_ms -= 500;
|
||||
client->schedule_ms -= 190;
|
||||
rate_add (source->format->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;
|
||||
@ -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.
|
||||
* 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;
|
||||
worker_t *this_worker = client->worker, *worker;
|
||||
int ret = 0;
|
||||
|
||||
thread_rwlock_rlock (&workers_lock);
|
||||
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)
|
||||
{
|
||||
thread_mutex_unlock (&source->lock);
|
||||
client_change_worker (client, worker);
|
||||
ret = client_change_worker (client, worker);
|
||||
if (ret)
|
||||
DEBUG2 ("moving source from %p to %p", this_worker, worker);
|
||||
else
|
||||
thread_mutex_lock (&source->lock);
|
||||
}
|
||||
}
|
||||
thread_rwlock_unlock (&workers_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* move listener client to worker theread that the source is on. This will
|
||||
* 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;
|
||||
long diff;
|
||||
int ret = 0;
|
||||
|
||||
thread_rwlock_rlock (&workers_lock);
|
||||
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)
|
||||
{
|
||||
thread_mutex_unlock (&source->lock);
|
||||
client_change_worker (client, dest_worker);
|
||||
ret = client_change_worker (client, dest_worker);
|
||||
if (ret)
|
||||
DEBUG2 ("moving listener from %p to %p", this_worker, dest_worker);
|
||||
else
|
||||
thread_mutex_lock (&source->lock);
|
||||
}
|
||||
thread_rwlock_unlock (&workers_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ void source_listener_detach (client_t *client);
|
||||
void source_main(source_t *source);
|
||||
void source_recheck_mounts (int update_all);
|
||||
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_init (source_t *source);
|
||||
void source_shutdown (source_t *source, int with_fallback);
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[Setup]
|
||||
AppName=Icecast2-KH
|
||||
AppVerName=Icecast v2.3.2-kh16
|
||||
AppVerName=Icecast v2.3.2-kh17
|
||||
AppPublisherURL=http://www.icecast.org
|
||||
AppSupportURL=http://www.icecast.org
|
||||
AppUpdatesURL=http://www.icecast.org
|
||||
@ -13,10 +13,10 @@ AllowNoIcons=yes
|
||||
LicenseFile=..\COPYING
|
||||
InfoAfterFile=..\README
|
||||
OutputDir=.
|
||||
OutputBaseFilename=icecast2_win32_v2.3.2-kh16_setup
|
||||
OutputBaseFilename=icecast2_win32_v2.3.2-kh17_setup
|
||||
WizardImageFile=icecast2logo2.bmp
|
||||
WizardImageStretch=no
|
||||
VersionInfoProductVersion=kh16
|
||||
VersionInfoProductVersion=kh17
|
||||
VersionInfoVersion=2.3.2
|
||||
; uncomment the following line if you want your installation to run on NT 3.51 too.
|
||||
; MinVersion=4,3.51
|
||||
|
Loading…
Reference in New Issue
Block a user