Commit ed019c0c authored by Michael Smith's avatar Michael Smith

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
parent 8651aabc
......@@ -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;
......
......@@ -7,20 +7,14 @@
#include <stdlib.h>
#include <string.h>
#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)
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment