Commit 76fc6281 authored by Michael Smith's avatar Michael Smith

Fix a serious bug with source creation in relays when local-mount != mount,

and fix a series of locking bugs in source creation.

svn path=/trunk/icecast/; revision=4352
parent 8f0aefb2
...@@ -290,6 +290,9 @@ static connection_t *_get_connection(void) ...@@ -290,6 +290,9 @@ static connection_t *_get_connection(void)
return con; return con;
} }
/* TODO: Make this return an appropriate error code so that we can use HTTP
* codes where appropriate
*/
int connection_create_source(client_t *client, connection_t *con, http_parser_t *parser, char *mount) { int connection_create_source(client_t *client, connection_t *con, http_parser_t *parser, char *mount) {
source_t *source; source_t *source;
char *contenttype; char *contenttype;
...@@ -306,7 +309,7 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t ...@@ -306,7 +309,7 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t
} }
global.sources++; global.sources++;
global_unlock(); global_unlock();
stats_event_inc(NULL, "sources"); stats_event_inc(NULL, "sources");
contenttype = httpp_getvar(parser, "content-type"); contenttype = httpp_getvar(parser, "content-type");
...@@ -324,6 +327,21 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t ...@@ -324,6 +327,21 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t
ERROR0("No content-type header, falling back to backwards compatibility mode for icecast 1.x relays. Assuming content is mp3."); ERROR0("No content-type header, falling back to backwards compatibility mode for icecast 1.x relays. Assuming content is mp3.");
source = source_create(client, con, parser, mount, format); source = source_create(client, con, parser, mount, format);
} }
/* We did a preliminary check earlier, to catch the common case before
* we do any unneccesary processing. Now, we do a check that must be
* correct - so we have to take a write lock out, since we need to
* add this source if it doesn't already exist.
*/
avl_tree_wlock(global.source_tree);
if (source_find_mount(mount) != NULL) {
INFO1("Source tried to log in as %s, but mountpoint is already used",
mount);
avl_tree_unlock(global.source_tree);
goto fail;
}
/* Keep the tree locked - it gets unlocked in source_main */
client->respcode = 200; client->respcode = 200;
bytes = sock_write(client->con->sock, bytes = sock_write(client->con->sock,
"HTTP/1.0 200 OK\r\n\r\n"); "HTTP/1.0 200 OK\r\n\r\n");
...@@ -569,15 +587,15 @@ static void _handle_source_request(connection_t *con, ...@@ -569,15 +587,15 @@ static void _handle_source_request(connection_t *con,
avl_tree_rlock(global.source_tree); avl_tree_rlock(global.source_tree);
if (source_find_mount(uri) != NULL) { if (source_find_mount(uri) != NULL) {
avl_tree_unlock(global.source_tree);
INFO1("Source tried to log in as %s, but mountpoint is already used", uri); INFO1("Source tried to log in as %s, but mountpoint is already used", uri);
client_send_404(client, "Mountpoint in use"); client_send_404(client, "Mountpoint in use");
avl_tree_unlock(global.source_tree);
return; return;
} }
avl_tree_unlock(global.source_tree); avl_tree_unlock(global.source_tree);
if (!connection_create_source(client, con, parser, uri)) { if (!connection_create_source(client, con, parser, uri)) {
client_destroy(client); client_send_404(client, "Mountpoint in use");
} }
} }
......
...@@ -180,7 +180,7 @@ static void *_slave_thread(void *arg) { ...@@ -180,7 +180,7 @@ static void *_slave_thread(void *arg) {
relay = config_get_config()->relay; relay = config_get_config()->relay;
while(relay) { while(relay) {
avl_tree_rlock(global.source_tree); avl_tree_rlock(global.source_tree);
if(!source_find_mount(relay->mount)) { if(!source_find_mount(relay->localmount)) {
avl_tree_unlock(global.source_tree); avl_tree_unlock(global.source_tree);
create_relay_stream(relay->server, relay->port, relay->mount, create_relay_stream(relay->server, relay->port, relay->mount,
......
...@@ -48,7 +48,7 @@ source_t *source_create(client_t *client, connection_t *con, http_parser_t *pars ...@@ -48,7 +48,7 @@ source_t *source_create(client_t *client, connection_t *con, http_parser_t *pars
src->client = client; src->client = client;
src->mount = (char *)strdup(mount); src->mount = (char *)strdup(mount);
src->fallback_mount = NULL; src->fallback_mount = NULL;
src->format = format_get_plugin(type, src->mount); src->format = format_get_plugin(type, src->mount, parser);
src->con = con; src->con = con;
src->parser = parser; src->parser = parser;
src->client_tree = avl_tree_new(_compare_clients, NULL); src->client_tree = avl_tree_new(_compare_clients, NULL);
...@@ -129,6 +129,9 @@ int source_free_source(void *key) ...@@ -129,6 +129,9 @@ int source_free_source(void *key)
} }
/* The caller MUST have a current write lock on global.source_tree when calling
* this
*/
void *source_main(void *arg) void *source_main(void *arg)
{ {
source_t *source = (source_t *)arg; source_t *source = (source_t *)arg;
...@@ -154,8 +157,8 @@ void *source_main(void *arg) ...@@ -154,8 +157,8 @@ void *source_main(void *arg)
/* grab a read lock, to make sure we get a chance to cleanup */ /* grab a read lock, to make sure we get a chance to cleanup */
thread_rwlock_rlock(source->shutdown_rwlock); thread_rwlock_rlock(source->shutdown_rwlock);
/* get a write lock on the global source tree */ /* The caller has ensured we have a write lock on the tree... */
avl_tree_wlock(global.source_tree);
/* insert source onto source tree */ /* insert source onto source tree */
avl_insert(global.source_tree, (void *)source); avl_insert(global.source_tree, (void *)source);
/* release write lock on global source tree */ /* release write lock on global source tree */
......
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