diff --git a/src/client.c b/src/client.c index ea350218..11fdfc5d 100644 --- a/src/client.c +++ b/src/client.c @@ -69,6 +69,17 @@ void client_send_404(client_t *client, char *message) { client_destroy(client); } +void client_send_504(client_t *client, char *message) { + int bytes; + client->respcode = 504; + bytes = sock_write(client->con->sock, + "HTTP/1.0 504 Server Full\r\n" + "Content-Type: text/html\r\n\r\n" + "%s\r\n", message); + if (bytes > 0) client->con->sent_bytes = bytes; + client_destroy(client); +} + void client_send_401(client_t *client) { int bytes = sock_write(client->con->sock, "HTTP/1.0 401 Authentication Required\r\n" diff --git a/src/client.h b/src/client.h index 4ae65bf3..310584d2 100644 --- a/src/client.h +++ b/src/client.h @@ -29,6 +29,7 @@ typedef struct _client_tag client_t *client_create(connection_t *con, http_parser_t *parser); void client_destroy(client_t *client); +void client_send_504(client_t *client, char *message); void client_send_404(client_t *client, char *message); void client_send_401(client_t *client); void client_send_400(client_t *client, char *message); diff --git a/src/connection.c b/src/connection.c index ef73fb5f..52f1e14f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -296,6 +296,7 @@ static connection_t *_get_connection(void) int connection_create_source(client_t *client, connection_t *con, http_parser_t *parser, char *mount) { source_t *source; char *contenttype; + mount_proxy *mountproxy, *mountinfo = NULL; /* check to make sure this source wouldn't ** be over the limit @@ -310,6 +311,15 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t global_unlock(); stats_event_inc(NULL, "sources"); + + mountproxy = config_get_config()->mounts; + while(mountproxy) { + if(!strcmp(mountproxy->mountname, mount)) { + mountinfo = mountproxy; + break; + } + mountproxy = mountproxy->next; + } contenttype = httpp_getvar(parser, "content-type"); @@ -319,12 +329,13 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t WARN1("Content-type \"%s\" not supported, dropping source", contenttype); goto fail; } else { - source = source_create(client, con, parser, mount, format); + source = source_create(client, con, parser, mount, + format, mountinfo); } } else { format_type_t format = FORMAT_TYPE_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, mountinfo); } source->send_return = 1; @@ -762,13 +773,8 @@ static void _handle_get_request(connection_t *con, global_lock(); if (global.clients >= config_get_config()->client_limit) { - client->respcode = 504; - bytes = sock_write(client->con->sock, - "HTTP/1.0 504 Server Full\r\n" - "Content-Type: text/html\r\n\r\n" - "The server is already full. Try again later.\r\n"); - if (bytes > 0) client->con->sent_bytes = bytes; - client_destroy(client); + client_send_504(client, + "The server is already full. Try again later."); global_unlock(); return; } @@ -781,18 +787,23 @@ static void _handle_get_request(connection_t *con, global_lock(); if (global.clients >= config_get_config()->client_limit) { - client->respcode = 504; - bytes = sock_write(client->con->sock, - "HTTP/1.0 504 Server Full\r\n" - "Content-Type: text/html\r\n\r\n" - "The server is already full. Try again later.\r\n"); - if (bytes > 0) client->con->sent_bytes = bytes; - client_destroy(client); + client_send_504(client, + "The server is already full. Try again later."); global_unlock(); avl_tree_unlock(global.source_tree); return; } + else if(source->max_listeners != -1 && + source->listeners >= source->max_listeners) + { + client_send_504(client, + "Too many clients on this mountpoint. Try again later."); + global_unlock(); + avl_tree_unlock(global.source_tree); + return; + } global.clients++; + source->listeners++; global_unlock(); client->format_data = source->format->create_client_data( diff --git a/src/source.c b/src/source.c index 300f49ab..b8274cab 100644 --- a/src/source.c +++ b/src/source.c @@ -3,6 +3,7 @@ #include #include #include +#include #ifndef _WIN32 #include @@ -55,7 +56,8 @@ static void _add_yp_info(source_t *source, char *stat_name, void *info, int type); source_t *source_create(client_t *client, connection_t *con, - http_parser_t *parser, const char *mount, format_type_t type) + http_parser_t *parser, const char *mount, format_type_t type, + mount_proxy *mountinfo) { int i = 0; source_t *src; @@ -73,6 +75,8 @@ source_t *source_create(client_t *client, connection_t *con, src->num_yp_directories = 0; src->listeners = 0; src->send_return = 0; + src->dumpfilename = NULL; + src->dumpfile = NULL; src->audio_info = util_dict_new(); for (i=0;inum_yp_directories;i++) { if (config_get_config()->yp_url[i]) { @@ -86,6 +90,20 @@ source_t *source_create(client_t *client, connection_t *con, } } + if(mountinfo != NULL) { + src->fallback_mount = mountinfo->fallback_mount; + src->max_listeners = mountinfo->max_listeners; + src->dumpfilename = mountinfo->dumpfile; + } + + if(src->dumpfilename != NULL) { + src->dumpfile = fopen(src->dumpfilename, "ab"); + if(src->dumpfile == NULL) { + WARN2("Cannot open dump file \"%s\" for appending: %s, disabling.", + src->dumpfilename, strerror(errno)); + } + } + return src; } @@ -170,7 +188,6 @@ void *source_main(void *arg) int listeners = 0; int i=0; int suppress_yp = 0; - util_dict *audio_info; char *ai; long queue_limit = config_get_config()->queue_size_limit; @@ -378,6 +395,18 @@ void *source_main(void *arg) ** to catch back up if it can */ + /* First, stream dumping, if enabled */ + if(source->dumpfile) { + if(fwrite(refbuf->data, 1, refbuf->len, source->dumpfile) != + refbuf->len) + { + WARN1("Write to dump file failed, disabling: %s", + strerror(errno)); + fclose(source->dumpfile); + source->dumpfile = NULL; + } + } + /* acquire read lock on client_tree */ avl_tree_rlock(source->client_tree); @@ -586,6 +615,9 @@ done: avl_delete(global.source_tree, source, source_free_source); avl_tree_unlock(global.source_tree); + if(source->dumpfile) + fclose(source->dumpfile); + thread_exit(0); return NULL; diff --git a/src/source.h b/src/source.h index 4a2701a8..842005b2 100644 --- a/src/source.h +++ b/src/source.h @@ -6,6 +6,8 @@ #include "util.h" #include "format.h" +#include + typedef struct source_tag { client_t *client; @@ -29,13 +31,19 @@ typedef struct source_tag rwlock_t *shutdown_rwlock; ypdata_t *ypdata[MAX_YP_DIRECTORIES]; util_dict *audio_info; + + char *dumpfilename; /* Name of a file to dump incoming stream to */ + FILE *dumpfile; + int num_yp_directories; long listeners; long max_listeners; int send_return; } source_t; -source_t *source_create(client_t *client, connection_t *con, http_parser_t *parser, const char *mount, format_type_t type); +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); int source_compare_sources(void *arg, void *a, void *b); int source_free_source(void *key); diff --git a/src/util.c b/src/util.c index cd49d582..666fab2c 100644 --- a/src/util.c +++ b/src/util.c @@ -414,6 +414,7 @@ const char *util_dict_get(util_dict *dict, const char *key) return dict->val; dict = dict->next; } + return NULL; } int util_dict_set(util_dict *dict, const char *key, const char *val) @@ -521,3 +522,4 @@ char *util_dict_urlencode(util_dict *dict, char delim) return res; } +