From ed019c0cd6c31fbdc5f9e199db2816f63ce82277 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Sun, 30 Mar 2003 13:52:27 +0000 Subject: [PATCH] Remove locking from refbuf: we used a single global lock for all of them, which caused significant lock contention with many sources. Further, a single refbuf is never used by more than one source (and hence one thread), so the locking was unneeded. Fix a nasty bug in source.c:_compare_clients() - was casting a void pointer to the wrong type, and hence all the tree-maintaince comparisons were totally wrong (but due to the exact nature of the bug this wasn't causing any active problems until...) Add another admin command to kill a client - remove it using an id. Note that many clients will do auto-reconnect, so this may not be sufficient on its own, we might need a ban (possibly temporary) function. svn path=/trunk/icecast/; revision=4569 --- src/admin.c | 37 +++++++++++++++++++++++++++++++++++++ src/refbuf.c | 11 +---------- src/source.c | 27 +++++++++++++++++++++++++-- src/source.h | 1 + 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/admin.c b/src/admin.c index 45e21121..01ec1ee9 100644 --- a/src/admin.c +++ b/src/admin.c @@ -32,6 +32,9 @@ #define COMMAND_RAW_STATS 102 #define COMMAND_RAW_LISTSTREAM 103 +/* Client management commands */ +#define COMMAND_KILL_CLIENT 201 + int admin_get_command(char *command) { if(!strcmp(command, "fallbacks")) @@ -50,6 +53,8 @@ int admin_get_command(char *command) return COMMAND_RAW_LISTSTREAM; else if(!strcmp(command, "moveclients")) return COMMAND_MOVE_CLIENTS; + else if(!strcmp(command, "killclient")) + return COMMAND_KILL_CLIENT; else return COMMAND_ERROR; } @@ -62,6 +67,8 @@ static void command_move_clients(client_t *client, source_t *source); static void command_raw_stats(client_t *client); static void command_list_mounts(client_t *client, int formatted); +static void command_kill_client(client_t *client, source_t *source); + static void admin_handle_mount_request(client_t *client, source_t *source, int command); static void admin_handle_general_request(client_t *client, int command); @@ -167,6 +174,9 @@ static void admin_handle_mount_request(client_t *client, source_t *source, case COMMAND_MOVE_CLIENTS: command_move_clients(client, source); break; + case COMMAND_KILL_CLIENT: + command_kill_client(client, source); + break; default: WARN0("Mount request not recognised"); client_send_400(client, "Mount request unknown"); @@ -290,6 +300,33 @@ static void command_show_listeners(client_t *client, source_t *source) client_destroy(client); } +static void command_kill_client(client_t *client, source_t *source) +{ + char *idtext; + int id; + client_t *listener; + + COMMAND_REQUIRE(client, "id", idtext); + + id = atoi(idtext); + + listener = source_find_client(source, id); + + if(listener != NULL) { + INFO1("Admin request: client %d removed", id); + + /* This tags it for removal on the next iteration of the main source + * loop + */ + listener->con->error = 1; + + html_success(client, "Client removed"); + } + else { + html_success(client, "Client not found"); + } +} + static void command_fallback(client_t *client, source_t *source) { char *fallback; diff --git a/src/refbuf.c b/src/refbuf.c index eef93924..d11ed4a4 100644 --- a/src/refbuf.c +++ b/src/refbuf.c @@ -7,20 +7,14 @@ #include #include -#include "thread.h" - #include "refbuf.h" -mutex_t _refbuf_mutex; - void refbuf_initialize(void) { - thread_mutex_create(&_refbuf_mutex); } void refbuf_shutdown(void) { - thread_mutex_destroy(&_refbuf_mutex); } refbuf_t *refbuf_new(unsigned long size) @@ -37,20 +31,17 @@ refbuf_t *refbuf_new(unsigned long size) void refbuf_addref(refbuf_t *self) { - thread_mutex_lock(&_refbuf_mutex); self->_count++; - thread_mutex_unlock(&_refbuf_mutex); } void refbuf_release(refbuf_t *self) { - thread_mutex_lock(&_refbuf_mutex); self->_count--; if (self->_count == 0) { free(self->data); free(self); + return; } - thread_mutex_unlock(&_refbuf_mutex); } void refbuf_queue_add(refbuf_queue_t **queue, refbuf_t *refbuf) diff --git a/src/source.c b/src/source.c index 9f65ccc9..e9072012 100644 --- a/src/source.c +++ b/src/source.c @@ -164,6 +164,26 @@ int source_free_source(void *key) return 1; } + +client_t *source_find_client(source_t *source, int id) +{ + client_t fakeclient; + client_t *result; + connection_t fakecon; + + fakeclient.con = &fakecon; + fakeclient.con->id = id; + + avl_tree_rlock(source->client_tree); + if(avl_get_by_key(source->client_tree, &fakeclient, (void **)&result) == 0) + { + avl_tree_unlock(source->client_tree); + return result; + } + + avl_tree_unlock(source->client_tree); + return NULL; +} void *source_main(void *arg) @@ -657,8 +677,11 @@ done: static int _compare_clients(void *compare_arg, void *a, void *b) { - connection_t *cona = (connection_t *)a; - connection_t *conb = (connection_t *)b; + client_t *clienta = (client_t *)a; + client_t *clientb = (client_t *)b; + + connection_t *cona = clienta->con; + connection_t *conb = clientb->con; if (cona->id < conb->id) return -1; if (cona->id > conb->id) return 1; diff --git a/src/source.h b/src/source.h index d03890e1..8dd15f0d 100644 --- a/src/source.h +++ b/src/source.h @@ -45,6 +45,7 @@ source_t *source_create(client_t *client, connection_t *con, http_parser_t *parser, const char *mount, format_type_t type, mount_proxy *mountinfo); source_t *source_find_mount(const char *mount); +client_t *source_find_client(source_t *source, int id); int source_compare_sources(void *arg, void *a, void *b); int source_free_source(void *key); int source_remove_client(void *key);