mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-01-03 14:56:34 -05:00
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
This commit is contained in:
parent
8651aabcbb
commit
ed019c0cd6
37
src/admin.c
37
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;
|
||||
|
11
src/refbuf.c
11
src/refbuf.c
@ -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)
|
||||
|
27
src/source.c
27
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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user