diff --git a/ChangeLog b/News similarity index 88% rename from ChangeLog rename to News index 5dd93489..5460af00 100644 --- a/ChangeLog +++ b/News @@ -1,5 +1,7 @@ -(Note: from here on, the changelog generally only includes new features, not -bug fixes) +2003-03-05 + Implemented the ability to reread the config file on SIGHUP. For now, this + does not affect configuration for currently running sources (only new + sources and global parameters like max-listeners) 2003-03-02 More features: diff --git a/TODO b/TODO index 6f4e9f18..246a5e2b 100644 --- a/TODO +++ b/TODO @@ -50,6 +50,8 @@ FEATURES - option to use ipv6 (equiv to using ::, I think. -- per-mountpoint listener maximums. - +- abstract all admin functionality to a set of commands, and command handlers. + Make /admin/* just parse according to a set of rules, and dispatch generic + commands through that. + Use this for alternative admin interfaces (GUI? telnet interface?) diff --git a/src/Makefile.am b/src/Makefile.am index 83f391df..aa2d5d9e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,10 +8,10 @@ bin_PROGRAMS = icecast noinst_HEADERS = config.h os.h logging.h sighandler.h connection.h global.h\ util.h slave.h source.h stats.h refbuf.h client.h format.h format_vorbis.h\ - compat.h format_mp3.h fserve.h xslt.h geturl.h yp.h + compat.h format_mp3.h fserve.h xslt.h geturl.h yp.h event.h icecast_SOURCES = config.c main.c logging.c sighandler.c connection.c global.c\ util.c slave.c source.c stats.c refbuf.c client.c format.c format_vorbis.c\ - format_mp3.c xslt.c fserve.c geturl.c yp.c + format_mp3.c xslt.c fserve.c geturl.c yp.c event.c icecast_LDADD = net/libicenet.la thread/libicethread.la httpp/libicehttpp.la\ log/libicelog.la avl/libiceavl.la timing/libicetiming.la diff --git a/src/config.c b/src/config.c index c65525cc..12fa9144 100644 --- a/src/config.c +++ b/src/config.c @@ -3,6 +3,8 @@ #include #include #include + +#include "thread/thread.h" #include "config.h" #include "refbuf.h" #include "client.h" @@ -45,36 +47,59 @@ #define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot" #endif -ice_config_t _configuration; -char *_config_filename; +ice_config_t _current_configuration; +ice_config_locks _locks; -static void _set_defaults(void); -static void _parse_root(xmlDocPtr doc, xmlNodePtr node); -static void _parse_limits(xmlDocPtr doc, xmlNodePtr node); -static void _parse_directory(xmlDocPtr doc, xmlNodePtr node); -static void _parse_paths(xmlDocPtr doc, xmlNodePtr node); -static void _parse_logging(xmlDocPtr doc, xmlNodePtr node); -static void _parse_security(xmlDocPtr doc, xmlNodePtr node); -static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node); -static void _parse_relay(xmlDocPtr doc, xmlNodePtr node); -static void _parse_mount(xmlDocPtr doc, xmlNodePtr node); -static void _add_server(xmlDocPtr doc, xmlNodePtr node); +static void _set_defaults(ice_config_t *c); +static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *c); +static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); -void config_initialize(void) -{ - memset(&_configuration, 0, sizeof(ice_config_t)); - _set_defaults(); - _config_filename = NULL; +static void create_locks() { + thread_mutex_create(&_locks.relay_lock); + thread_mutex_create(&_locks.mounts_lock); + thread_mutex_create(&_locks.config_lock); } -void config_shutdown(void) +static void release_locks() { + thread_mutex_destroy(&_locks.relay_lock); + thread_mutex_destroy(&_locks.mounts_lock); + thread_mutex_destroy(&_locks.config_lock); +} + +void config_initialize(void) { + create_locks(); +} + +void config_shutdown(void) { + config_get_config(); + config_clear(&_current_configuration); + config_release_config(); + release_locks(); +} + +void config_init_configuration(ice_config_t *configuration) +{ + memset(configuration, 0, sizeof(ice_config_t)); + _set_defaults(configuration); +} + +void config_clear(ice_config_t *c) { ice_config_dir_t *dirnode, *nextdirnode; - ice_config_t *c = &_configuration; relay_server *relay, *nextrelay; mount_proxy *mount, *nextmount; - if (_config_filename) free(_config_filename); + if (c->config_filename) + free(c->config_filename); if (c->location && c->location != CONFIG_DEFAULT_LOCATION) xmlFree(c->location); @@ -105,7 +130,9 @@ void config_shutdown(void) if (c->master_password) xmlFree(c->master_password); if (c->user) xmlFree(c->user); if (c->group) xmlFree(c->group); - relay = _configuration.relay; + + thread_mutex_lock(&(_locks.relay_lock)); + relay = c->relay; while(relay) { nextrelay = relay->next; xmlFree(relay->server); @@ -115,7 +142,10 @@ void config_shutdown(void) free(relay); relay = nextrelay; } - mount = _configuration.mounts; + thread_mutex_unlock(&(_locks.relay_lock)); + + thread_mutex_lock(&(_locks.mounts_lock)); + mount = c->mounts; while(mount) { nextmount = mount->next; xmlFree(mount->mountname); @@ -126,7 +156,9 @@ void config_shutdown(void) free(mount); mount = nextmount; } - dirnode = _configuration.dir_list; + thread_mutex_unlock(&(_locks.mounts_lock)); + + dirnode = c->dir_list; while(dirnode) { nextdirnode = dirnode->next; xmlFree(dirnode->host); @@ -137,17 +169,21 @@ void config_shutdown(void) memset(c, 0, sizeof(ice_config_t)); } -int config_parse_file(const char *filename) +int config_initial_parse_file(const char *filename) +{ + /* Since we're already pointing at it, we don't need to copy it in place */ + return config_parse_file(filename, &_current_configuration); +} + +int config_parse_file(const char *filename, ice_config_t *configuration) { xmlDocPtr doc; xmlNodePtr node; if (filename == NULL || strcmp(filename, "") == 0) return CONFIG_EINSANE; - _config_filename = (char *)strdup(filename); - xmlInitParser(); - doc = xmlParseFile(_config_filename); + doc = xmlParseFile(filename); if (doc == NULL) { return CONFIG_EPARSE; } @@ -165,7 +201,11 @@ int config_parse_file(const char *filename) return CONFIG_EBADROOT; } - _parse_root(doc, node->xmlChildrenNode); + config_init_configuration(configuration); + + configuration->config_filename = (char *)strdup(filename); + + _parse_root(doc, node->xmlChildrenNode, configuration); xmlFreeDoc(doc); xmlCleanupParser(); @@ -178,54 +218,71 @@ int config_parse_cmdline(int arg, char **argv) return 0; } -int config_rehash(void) +ice_config_locks *config_locks(void) { - return 0; + return &_locks; +} + +void config_release_config(void) +{ + thread_mutex_unlock(&(_locks.config_lock)); } ice_config_t *config_get_config(void) { - return &_configuration; + thread_mutex_lock(&(_locks.config_lock)); + return &_current_configuration; } -static void _set_defaults(void) +/* MUST be called with the lock held! */ +void config_set_config(ice_config_t *config) { + memcpy(&_current_configuration, config, sizeof(ice_config_t)); +} + +ice_config_t *config_get_config_unlocked(void) { - _configuration.location = CONFIG_DEFAULT_LOCATION; - _configuration.admin = CONFIG_DEFAULT_ADMIN; - _configuration.client_limit = CONFIG_DEFAULT_CLIENT_LIMIT; - _configuration.source_limit = CONFIG_DEFAULT_SOURCE_LIMIT; - _configuration.queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT; - _configuration.threadpool_size = CONFIG_DEFAULT_THREADPOOL_SIZE; - _configuration.client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT; - _configuration.header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT; - _configuration.source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT; - _configuration.source_password = CONFIG_DEFAULT_SOURCE_PASSWORD; - _configuration.relay_password = CONFIG_DEFAULT_RELAY_PASSWORD; - _configuration.ice_login = CONFIG_DEFAULT_ICE_LOGIN; - _configuration.fileserve = CONFIG_DEFAULT_FILESERVE; - _configuration.touch_interval = CONFIG_DEFAULT_TOUCH_FREQ; - _configuration.dir_list = NULL; - _configuration.hostname = CONFIG_DEFAULT_HOSTNAME; - _configuration.port = CONFIG_DEFAULT_PORT; - _configuration.bind_address = NULL; - _configuration.master_server = NULL; - _configuration.master_server_port = CONFIG_DEFAULT_PORT; - _configuration.master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL; - _configuration.master_password = NULL; - _configuration.base_dir = CONFIG_DEFAULT_BASE_DIR; - _configuration.log_dir = CONFIG_DEFAULT_LOG_DIR; - _configuration.webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR; - _configuration.access_log = CONFIG_DEFAULT_ACCESS_LOG; - _configuration.error_log = CONFIG_DEFAULT_ERROR_LOG; - _configuration.loglevel = CONFIG_DEFAULT_LOG_LEVEL; - _configuration.chroot = CONFIG_DEFAULT_CHROOT; - _configuration.chuid = CONFIG_DEFAULT_CHUID; - _configuration.user = CONFIG_DEFAULT_USER; - _configuration.group = CONFIG_DEFAULT_GROUP; - _configuration.num_yp_directories = 0; + return &_current_configuration; } -static void _parse_root(xmlDocPtr doc, xmlNodePtr node) +static void _set_defaults(ice_config_t *configuration) +{ + configuration->location = CONFIG_DEFAULT_LOCATION; + configuration->admin = CONFIG_DEFAULT_ADMIN; + configuration->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT; + configuration->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT; + configuration->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT; + configuration->threadpool_size = CONFIG_DEFAULT_THREADPOOL_SIZE; + configuration->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT; + configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT; + configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT; + configuration->source_password = CONFIG_DEFAULT_SOURCE_PASSWORD; + configuration->relay_password = CONFIG_DEFAULT_RELAY_PASSWORD; + configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN; + configuration->fileserve = CONFIG_DEFAULT_FILESERVE; + configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ; + configuration->dir_list = NULL; + configuration->hostname = CONFIG_DEFAULT_HOSTNAME; + configuration->port = CONFIG_DEFAULT_PORT; + configuration->bind_address = NULL; + configuration->master_server = NULL; + configuration->master_server_port = CONFIG_DEFAULT_PORT; + configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL; + configuration->master_password = NULL; + configuration->base_dir = CONFIG_DEFAULT_BASE_DIR; + configuration->log_dir = CONFIG_DEFAULT_LOG_DIR; + configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR; + configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG; + configuration->error_log = CONFIG_DEFAULT_ERROR_LOG; + configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL; + configuration->chroot = CONFIG_DEFAULT_CHROOT; + configuration->chuid = CONFIG_DEFAULT_CHUID; + configuration->user = CONFIG_DEFAULT_USER; + configuration->group = CONFIG_DEFAULT_GROUP; + configuration->num_yp_directories = 0; +} + +static void _parse_root(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { char *tmp; @@ -234,13 +291,13 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node) if (xmlIsBlankNode(node)) continue; if (strcmp(node->name, "location") == 0) { - if (_configuration.location && _configuration.location != CONFIG_DEFAULT_LOCATION) xmlFree(_configuration.location); - _configuration.location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->location && configuration->location != CONFIG_DEFAULT_LOCATION) xmlFree(configuration->location); + configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "admin") == 0) { - if (_configuration.admin && _configuration.admin != CONFIG_DEFAULT_ADMIN) xmlFree(_configuration.admin); - _configuration.admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->admin && configuration->admin != CONFIG_DEFAULT_ADMIN) xmlFree(configuration->admin); + configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if(strcmp(node->name, "authentication") == 0) { - _parse_authentication(doc, node->xmlChildrenNode); + _parse_authentication(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "source-password") == 0) { /* TODO: This is the backwards-compatibility location */ char *mount, *pass; @@ -249,62 +306,63 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node) /* FIXME: This is a placeholder for per-mount passwords */ } else { - if (_configuration.source_password && _configuration.source_password != CONFIG_DEFAULT_SOURCE_PASSWORD) xmlFree(_configuration.source_password); - _configuration.source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->source_password && configuration->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD) xmlFree(configuration->source_password); + configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } else if (strcmp(node->name, "relay-password") == 0) { /* TODO: This is the backwards-compatibility location */ - if (_configuration.relay_password && _configuration.relay_password != CONFIG_DEFAULT_RELAY_PASSWORD) xmlFree(_configuration.relay_password); - _configuration.relay_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->relay_password && configuration->relay_password != CONFIG_DEFAULT_RELAY_PASSWORD) xmlFree(configuration->relay_password); + configuration->relay_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "icelogin") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.ice_login = atoi(tmp); + configuration->ice_login = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "fileserve") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.fileserve = atoi(tmp); + configuration->fileserve = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "hostname") == 0) { - if (_configuration.hostname && _configuration.hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(_configuration.hostname); - _configuration.hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->hostname && configuration->hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(configuration->hostname); + configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "port") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.port = atoi(tmp); + configuration->port = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "bind-address") == 0) { - if (_configuration.bind_address) xmlFree(_configuration.bind_address); - _configuration.bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->bind_address) xmlFree(configuration->bind_address); + configuration->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "master-server") == 0) { - if (_configuration.master_server) xmlFree(_configuration.master_server); - _configuration.master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->master_server) xmlFree(configuration->master_server); + configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "master-password") == 0) { - if (_configuration.master_password) xmlFree(_configuration.master_password); - _configuration.master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->master_password) xmlFree(configuration->master_password); + configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "master-server-port") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.master_server_port = atoi(tmp); + configuration->master_server_port = atoi(tmp); } else if (strcmp(node->name, "master-update-interval") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.master_update_interval = atoi(tmp); + configuration->master_update_interval = atoi(tmp); } else if (strcmp(node->name, "limits") == 0) { - _parse_limits(doc, node->xmlChildrenNode); + _parse_limits(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "relay") == 0) { - _parse_relay(doc, node->xmlChildrenNode); + _parse_relay(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "mount") == 0) { - _parse_mount(doc, node->xmlChildrenNode); + _parse_mount(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "directory") == 0) { - _parse_directory(doc, node->xmlChildrenNode); + _parse_directory(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "paths") == 0) { - _parse_paths(doc, node->xmlChildrenNode); + _parse_paths(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "logging") == 0) { - _parse_logging(doc, node->xmlChildrenNode); + _parse_logging(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "security") == 0) { - _parse_security(doc, node->xmlChildrenNode); + _parse_security(doc, node->xmlChildrenNode, configuration); } } while ((node = node->next)); } -static void _parse_limits(xmlDocPtr doc, xmlNodePtr node) +static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { char *tmp; @@ -314,41 +372,42 @@ static void _parse_limits(xmlDocPtr doc, xmlNodePtr node) if (strcmp(node->name, "clients") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.client_limit = atoi(tmp); + configuration->client_limit = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "sources") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.source_limit = atoi(tmp); + configuration->source_limit = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "queue-size") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.queue_size_limit = atoi(tmp); + configuration->queue_size_limit = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "threadpool") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.threadpool_size = atoi(tmp); + configuration->threadpool_size = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "client-timeout") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.client_timeout = atoi(tmp); + configuration->client_timeout = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "header-timeout") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.header_timeout = atoi(tmp); + configuration->header_timeout = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "source-timeout") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.source_timeout = atoi(tmp); + configuration->source_timeout = atoi(tmp); if (tmp) xmlFree(tmp); } } while ((node = node->next)); } -static void _parse_mount(xmlDocPtr doc, xmlNodePtr node) +static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { char *tmp; mount_proxy *mount = calloc(1, sizeof(mount_proxy)); - mount_proxy *current = _configuration.mounts; + mount_proxy *current = configuration->mounts; mount_proxy *last=NULL; while(current) { @@ -359,7 +418,7 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node) if(last) last->next = mount; else - _configuration.mounts = mount; + configuration->mounts = mount; mount->max_listeners = -1; @@ -395,11 +454,12 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node) } while ((node = node->next)); } -static void _parse_relay(xmlDocPtr doc, xmlNodePtr node) +static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { char *tmp; relay_server *relay = calloc(1, sizeof(relay_server)); - relay_server *current = _configuration.relay; + relay_server *current = configuration->relay; relay_server *last=NULL; while(current) { @@ -410,7 +470,7 @@ static void _parse_relay(xmlDocPtr doc, xmlNodePtr node) if(last) last->next = relay; else - _configuration.relay = relay; + configuration->relay = relay; do { if (node == NULL) break; @@ -441,7 +501,8 @@ static void _parse_relay(xmlDocPtr doc, xmlNodePtr node) } while ((node = node->next)); } -static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node) +static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { do { if (node == NULL) break; @@ -454,39 +515,40 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node) /* FIXME: This is a placeholder for per-mount passwords */ } else { - if (_configuration.source_password && - _configuration.source_password != + if (configuration->source_password && + configuration->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD) - xmlFree(_configuration.source_password); - _configuration.source_password = + xmlFree(configuration->source_password); + configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } else if (strcmp(node->name, "relay-password") == 0) { - if (_configuration.relay_password && - _configuration.relay_password != + if (configuration->relay_password && + configuration->relay_password != CONFIG_DEFAULT_RELAY_PASSWORD) - xmlFree(_configuration.relay_password); - _configuration.relay_password = + xmlFree(configuration->relay_password); + configuration->relay_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "admin-password") == 0) { - if(_configuration.admin_password) - xmlFree(_configuration.admin_password); - _configuration.admin_password = + if(configuration->admin_password) + xmlFree(configuration->admin_password); + configuration->admin_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "admin-user") == 0) { - if(_configuration.admin_username) - xmlFree(_configuration.admin_username); - _configuration.admin_username = + if(configuration->admin_username) + xmlFree(configuration->admin_username); + configuration->admin_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } while ((node = node->next)); } -static void _parse_directory(xmlDocPtr doc, xmlNodePtr node) +static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { char *tmp; - if (_configuration.num_yp_directories >= MAX_YP_DIRECTORIES) { + if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) { ERROR0("Maximum number of yp directories exceeded!"); return; } @@ -495,68 +557,71 @@ static void _parse_directory(xmlDocPtr doc, xmlNodePtr node) if (xmlIsBlankNode(node)) continue; if (strcmp(node->name, "yp-url") == 0) { - if (_configuration.yp_url[_configuration.num_yp_directories]) - xmlFree(_configuration.yp_url[_configuration.num_yp_directories]); - _configuration.yp_url[_configuration.num_yp_directories] = + if (configuration->yp_url[configuration->num_yp_directories]) + xmlFree(configuration->yp_url[configuration->num_yp_directories]); + configuration->yp_url[configuration->num_yp_directories] = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "yp-url-timeout") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.yp_url_timeout[_configuration.num_yp_directories] = + configuration->yp_url_timeout[configuration->num_yp_directories] = atoi(tmp); } else if (strcmp(node->name, "server") == 0) { - _add_server(doc, node->xmlChildrenNode); + _add_server(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "touch-interval") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.touch_interval = atoi(tmp); + configuration->touch_interval = atoi(tmp); if (tmp) xmlFree(tmp); } } while ((node = node->next)); - _configuration.num_yp_directories++; + configuration->num_yp_directories++; } -static void _parse_paths(xmlDocPtr doc, xmlNodePtr node) +static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (strcmp(node->name, "basedir") == 0) { - if (_configuration.base_dir && _configuration.base_dir != CONFIG_DEFAULT_BASE_DIR) xmlFree(_configuration.base_dir); - _configuration.base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->base_dir && configuration->base_dir != CONFIG_DEFAULT_BASE_DIR) xmlFree(configuration->base_dir); + configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "logdir") == 0) { - if (_configuration.log_dir && _configuration.log_dir != CONFIG_DEFAULT_LOG_DIR) xmlFree(_configuration.log_dir); - _configuration.log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->log_dir && configuration->log_dir != CONFIG_DEFAULT_LOG_DIR) xmlFree(configuration->log_dir); + configuration->log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "webroot") == 0) { - if (_configuration.webroot_dir && _configuration.webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) xmlFree(_configuration.webroot_dir); - _configuration.webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - if(_configuration.webroot_dir[strlen(_configuration.webroot_dir)-1] == '/') - _configuration.webroot_dir[strlen(_configuration.webroot_dir)-1] = 0; + if (configuration->webroot_dir && configuration->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) xmlFree(configuration->webroot_dir); + configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/') + configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0; } } while ((node = node->next)); } -static void _parse_logging(xmlDocPtr doc, xmlNodePtr node) +static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (strcmp(node->name, "accesslog") == 0) { - if (_configuration.access_log && _configuration.access_log != CONFIG_DEFAULT_ACCESS_LOG) xmlFree(_configuration.access_log); - _configuration.access_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->access_log && configuration->access_log != CONFIG_DEFAULT_ACCESS_LOG) xmlFree(configuration->access_log); + configuration->access_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "errorlog") == 0) { - if (_configuration.error_log && _configuration.error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(_configuration.error_log); - _configuration.error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->error_log && configuration->error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(configuration->error_log); + configuration->error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "loglevel") == 0) { char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.loglevel = atoi(tmp); + configuration->loglevel = atoi(tmp); if (tmp) xmlFree(tmp); } } while ((node = node->next)); } -static void _parse_security(xmlDocPtr doc, xmlNodePtr node) +static void _parse_security(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { char *tmp; xmlNodePtr oldnode; @@ -567,21 +632,21 @@ static void _parse_security(xmlDocPtr doc, xmlNodePtr node) if (strcmp(node->name, "chroot") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - _configuration.chroot = atoi(tmp); + configuration->chroot = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "changeowner") == 0) { - _configuration.chuid = 1; + configuration->chuid = 1; oldnode = node; node = node->xmlChildrenNode; do { if(node == NULL) break; if(xmlIsBlankNode(node)) continue; if(strcmp(node->name, "user") == 0) { - if(_configuration.user) xmlFree(_configuration.user); - _configuration.user = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if(configuration->user) xmlFree(configuration->user); + configuration->user = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if(strcmp(node->name, "group") == 0) { - if(_configuration.group) xmlFree(_configuration.group); - _configuration.group = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if(configuration->group) xmlFree(configuration->group); + configuration->group = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } while((node = node->next)); node = oldnode; @@ -589,14 +654,15 @@ static void _parse_security(xmlDocPtr doc, xmlNodePtr node) } while ((node = node->next)); } -static void _add_server(xmlDocPtr doc, xmlNodePtr node) +static void _add_server(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) { ice_config_dir_t *dirnode, *server; int addnode; char *tmp; server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t)); - server->touch_interval = _configuration.touch_interval; + server->touch_interval = configuration->touch_interval; server->host = NULL; addnode = 0; @@ -617,9 +683,9 @@ static void _add_server(xmlDocPtr doc, xmlNodePtr node) } while ((node = node->next)); if (addnode) { - dirnode = _configuration.dir_list; + dirnode = configuration->dir_list; if (dirnode == NULL) { - _configuration.dir_list = server; + configuration->dir_list = server; } else { while (dirnode->next) dirnode = dirnode->next; diff --git a/src/config.h b/src/config.h index 212856dd..99216173 100644 --- a/src/config.h +++ b/src/config.h @@ -8,6 +8,8 @@ #define MAX_YP_DIRECTORIES 25 +#include "thread/thread.h" + typedef struct ice_config_dir_tag { char *host; @@ -40,6 +42,8 @@ typedef struct _mount_proxy { typedef struct ice_config_tag { + char *config_filename; + char *location; char *admin; @@ -90,15 +94,30 @@ typedef struct ice_config_tag int num_yp_directories; } ice_config_t; +typedef struct { + mutex_t config_lock; + mutex_t relay_lock; + mutex_t mounts_lock; +} ice_config_locks; + void config_initialize(void); void config_shutdown(void); -int config_parse_file(const char *filename); +int config_parse_file(const char *filename, ice_config_t *configuration); +int config_initial_parse_file(const char *filename); int config_parse_cmdline(int arg, char **argv); +void config_set_config(ice_config_t *config); +void config_clear(ice_config_t *config); int config_rehash(void); +ice_config_locks *config_locks(void); + ice_config_t *config_get_config(void); +void config_release_config(void); + +/* To be used ONLY in one-time startup code */ +ice_config_t *config_get_config_unlocked(void); #endif /* __CONFIG_H__ */ diff --git a/src/configtest.c b/src/configtest.c index e98f8885..cc300dd0 100644 --- a/src/configtest.c +++ b/src/configtest.c @@ -11,7 +11,7 @@ int main(void) config_parse_file("icecast.xml"); - config = config_get_config(); + config = config_get_config_unlocked(); _dump_config(config); diff --git a/src/connection.c b/src/connection.c index d5355ab0..dcc8dd9e 100644 --- a/src/connection.c +++ b/src/connection.c @@ -40,6 +40,7 @@ #include "geturl.h" #include "format.h" #include "format_mp3.h" +#include "event.h" #define CATMODULE "connection" @@ -112,6 +113,10 @@ connection_t *create_connection(sock_t sock, char *ip) { con->con_time = time(NULL); con->id = _next_connection_id(); con->ip = ip; + + con->event_number = EVENT_NO_EVENT; + con->event = NULL; + return con; } @@ -209,10 +214,13 @@ static void _build_pool(void) int i; thread_type *tid; char buff[64]; + int threadpool_size; config = config_get_config(); + threadpool_size = config->threadpool_size; + config_release_config(); - for (i = 0; i < config->threadpool_size; i++) { + for (i = 0; i < threadpool_size; i++) { snprintf(buff, 64, "Connection Thread #%d", i); tid = thread_create(buff, _handle_connection, NULL, THREAD_ATTACHED); _push_thread(&_conhands, tid); @@ -290,6 +298,16 @@ static connection_t *_get_connection(void) return con; } +void connection_inject_event(int eventnum, void *event_data) { + connection_t *con = calloc(1, sizeof(connection_t)); + + con->event_number = eventnum; + con->event = event_data; + + _add_connection(con); + _signal_pool(); +} + /* TODO: Make this return an appropriate error code so that we can use HTTP * codes where appropriate */ @@ -297,12 +315,18 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t source_t *source; char *contenttype; mount_proxy *mountproxy, *mountinfo = NULL; + int source_limit; + ice_config_t *config; + + config = config_get_config(); + source_limit = config->source_limit; + config_release_config(); /* check to make sure this source wouldn't ** be over the limit */ global_lock(); - if (global.sources >= config_get_config()->source_limit) { + if (global.sources >= source_limit) { INFO1("Source (%s) logged in, but there are too many sources", mount); global_unlock(); return 0; @@ -312,7 +336,11 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t stats_event_inc(NULL, "sources"); - mountproxy = config_get_config()->mounts; + config = config_get_config(); + mountproxy = config->mounts; + thread_mutex_lock(&(config_locks()->mounts_lock)); + config_release_config(); + while(mountproxy) { if(!strcmp(mountproxy->mountname, mount)) { mountinfo = mountproxy; @@ -327,15 +355,18 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t format_type_t format = format_get_type(contenttype); if (format == FORMAT_ERROR) { WARN1("Content-type \"%s\" not supported, dropping source", contenttype); + thread_mutex_unlock(&(config_locks()->mounts_lock)); goto fail; } else { source = source_create(client, con, parser, mount, format, mountinfo); + thread_mutex_unlock(&(config_locks()->mounts_lock)); } } 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, mountinfo); + thread_mutex_unlock(&(config_locks()->mounts_lock)); } source->send_return = 1; @@ -408,17 +439,22 @@ static int _check_pass_ice(http_parser_t *parser, char *correctpass) static int _check_relay_pass(http_parser_t *parser) { - char *pass = config_get_config()->relay_password; + ice_config_t *config = config_get_config(); + char *pass = config->relay_password; if(!pass) - pass = config_get_config()->source_password; + pass = config->source_password; + config_release_config(); return _check_pass_http(parser, "relay", pass); } static int _check_admin_pass(http_parser_t *parser) { - char *pass = config_get_config()->admin_password; - char *user = config_get_config()->admin_username; + ice_config_t *config = config_get_config(); + char *pass = config->admin_password; + char *user = config->admin_username; + config_release_config(); + if(!pass || !user) return 0; @@ -427,11 +463,16 @@ static int _check_admin_pass(http_parser_t *parser) static int _check_source_pass(http_parser_t *parser, char *mount) { - char *pass = config_get_config()->source_password; + ice_config_t *config = config_get_config(); + char *pass = config->source_password; char *user = "source"; int ret; + int ice_login = config->ice_login; + + mount_proxy *mountinfo = config->mounts; + thread_mutex_lock(&(config_locks()->mounts_lock)); + config_release_config(); - mount_proxy *mountinfo = config_get_config()->mounts; while(mountinfo) { if(!strcmp(mountinfo->mountname, mount)) { if(mountinfo->password) @@ -443,13 +484,15 @@ static int _check_source_pass(http_parser_t *parser, char *mount) mountinfo = mountinfo->next; } + thread_mutex_unlock(&(config_locks()->mounts_lock)); + if(!pass) { WARN0("No source password set, rejecting source"); return 0; } ret = _check_pass_http(parser, user, pass); - if(!ret && config_get_config()->ice_login) + if(!ret && ice_login) { ret = _check_pass_ice(parser, pass); if(ret) @@ -627,6 +670,19 @@ static void _handle_get_request(connection_t *con, int bytes; struct stat statbuf; source_t *source; + int fileserve; + char *host; + int port; + ice_config_t *config; + int client_limit; + + config = config_get_config(); + fileserve = config->fileserve; + host = config->hostname; + port = config->port; + client_limit = config->client_limit; + config_release_config(); + DEBUG0("Client connected"); @@ -689,8 +745,8 @@ static void _handle_get_request(connection_t *con, free(fullpath); return; } - else if(config_get_config()->fileserve && - stat(fullpath, &statbuf) == 0) { + else if(fileserve && stat(fullpath, &statbuf) == 0) + { fserve_client_create(client, fullpath); free(fullpath); return; @@ -709,14 +765,14 @@ static void _handle_get_request(connection_t *con, "HTTP/1.0 200 OK\r\n" "Content-Type: audio/x-mpegurl\r\n\r\n" "http://%s:%d%s", - config_get_config()->hostname, - config_get_config()->port, + host, + port, sourceuri ); if(bytes > 0) client->con->sent_bytes = bytes; client_destroy(client); } - else if(config_get_config()->fileserve) { + else if(fileserve) { fullpath = util_get_path_from_normalised_uri(sourceuri); if(stat(fullpath, &statbuf) == 0) { fserve_client_create(client, fullpath); @@ -774,7 +830,7 @@ static void _handle_get_request(connection_t *con, } global_lock(); - if (global.clients >= config_get_config()->client_limit) { + if (global.clients >= client_limit) { client_send_504(client, "The server is already full. Try again later."); global_unlock(); @@ -788,7 +844,7 @@ static void _handle_get_request(connection_t *con, DEBUG0("Source found for client"); global_lock(); - if (global.clients >= config_get_config()->client_limit) { + if (global.clients >= client_limit) { client_send_504(client, "The server is already full. Try again later."); global_unlock(); @@ -847,6 +903,21 @@ static void *_handle_connection(void *arg) /* grab a connection and set the socket to blocking */ while ((con = _get_connection())) { + + /* Handle meta-connections */ + if(con->event_number > 0) { + switch(con->event_number) { + case EVENT_CONFIG_READ: + event_config_read(con->event); + break; + default: + ERROR1("Unknown event number: %d", con->event_number); + break; + } + free(con); + continue; + } + stats_event_inc(NULL, "connections"); sock_set_blocking(con->sock, SOCK_BLOCK); diff --git a/src/connection.h b/src/connection.h index 4653646d..c7272112 100644 --- a/src/connection.h +++ b/src/connection.h @@ -21,6 +21,10 @@ typedef struct connection_tag char *ip; char *host; + + /* For 'fake' connections */ + int event_number; + void *event; } connection_t; void connection_initialize(void); @@ -31,6 +35,8 @@ connection_t *create_connection(sock_t sock, char *ip); int connection_create_source(struct _client_tag *client, connection_t *con, http_parser_t *parser, char *mount); +void connection_inject_event(int eventnum, void *event_data); + extern rwlock_t _source_shutdown_rwlock; #endif /* __CONNECTION_H__ */ diff --git a/src/event.c b/src/event.c new file mode 100644 index 00000000..1a929c49 --- /dev/null +++ b/src/event.c @@ -0,0 +1,46 @@ +#include "event.h" +#include "config.h" + +#include "refbuf.h" +#include "client.h" +#include "logging.h" + +#define CATMODULE "event" + +void event_config_read(void *arg) +{ + int ret; + ice_config_t *config; + ice_config_t new_config; + /* reread config file */ + + config = config_get_config(); /* Both to get the lock, and to be able + to find out the config filename */ + ret = config_parse_file(config->config_filename, &new_config); + if(ret < 0) { + ERROR0("Error parsing config, not replacing existing config"); + switch(ret) { + case CONFIG_EINSANE: + ERROR0("Config filename null or blank"); + break; + case CONFIG_ENOROOT: + ERROR1("Root element not found in %s", config->config_filename); + break; + case CONFIG_EBADROOT: + ERROR1("Not an icecast2 config file: %s", + config->config_filename); + break; + default: + ERROR1("Parse error in reading %s", config->config_filename); + break; + } + config_release_config(); + } + else { + config_clear(config); + config_set_config(&new_config); + + config_release_config(); + } +} + diff --git a/src/event.h b/src/event.h new file mode 100644 index 00000000..ce52b9b8 --- /dev/null +++ b/src/event.h @@ -0,0 +1,9 @@ +#ifndef __EVENT_H__ +#define __EVENT_H__ + +#define EVENT_NO_EVENT 0 +#define EVENT_CONFIG_READ 1 + +void event_config_read(void *nothing); + +#endif /* __EVENT_H__ */ diff --git a/src/fserve.c b/src/fserve.c index 61e85d76..be6373f6 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -78,7 +78,12 @@ static void create_mime_mappings(char *fn); void fserve_initialize(void) { - if(!config_get_config()->fileserve) + ice_config_t *config = config_get_config(); + int serve = config->fileserve; + + config_release_config(); + + if(!serve) return; create_mime_mappings(MIMETYPESFILE); @@ -95,7 +100,12 @@ void fserve_initialize(void) void fserve_shutdown(void) { - if(!config_get_config()->fileserve) + ice_config_t *config = config_get_config(); + int serve = config->fileserve; + + config_release_config(); + + if(!serve) return; if(!run_fserv) @@ -345,6 +355,11 @@ int fserve_client_create(client_t *httpclient, char *path) { fserve_t *client = calloc(1, sizeof(fserve_t)); int bytes; + int client_limit; + ice_config_t *config = config_get_config(); + + client_limit = config->client_limit; + config_release_config(); client->file = fopen(path, "rb"); if(!client->file) { @@ -358,7 +373,7 @@ int fserve_client_create(client_t *httpclient, char *path) client->buf = malloc(BUFSIZE); global_lock(); - if(global.clients >= config_get_config()->client_limit) { + if(global.clients >= client_limit) { httpclient->respcode = 504; bytes = sock_write(httpclient->con->sock, "HTTP/1.0 504 Server Full\r\n" diff --git a/src/main.c b/src/main.c index 3abbe7ab..ed1ddd3c 100644 --- a/src/main.c +++ b/src/main.c @@ -125,7 +125,7 @@ static int _start_logging(void) { char fn_error[FILENAME_MAX]; char fn_access[FILENAME_MAX]; - ice_config_t *config = config_get_config(); + ice_config_t *config = config_get_config_unlocked(); if(strcmp(config->error_log, "-")) { snprintf(fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->error_log); @@ -157,9 +157,10 @@ static int _setup_socket(void) { ice_config_t *config; - config = config_get_config(); + config = config_get_config_unlocked(); global.serversock = sock_get_server_socket(config->port, config->bind_address); + if (global.serversock == SOCK_ERROR) return 0; @@ -180,7 +181,8 @@ static int _start_listening(void) static int _server_proc_init(void) { if (!_setup_socket()) { - fprintf(stderr, "Could not create listener socket on port %d\n", config_get_config()->port); + fprintf(stderr, "Could not create listener socket on port %d\n", + config_get_config_unlocked()->port); return 0; } @@ -205,7 +207,7 @@ static void _server_proc(void) static void _ch_root_uid_setup(void) { - ice_config_t *conf = config_get_config(); + ice_config_t *conf = config_get_config_unlocked(); #ifdef CHUID struct passwd *user; struct group *group; @@ -291,7 +293,9 @@ int main(int argc, char **argv) _initialize_subsystems(); /* parse the config file */ - ret = config_parse_file(filename); + config_get_config(); + ret = config_initial_parse_file(filename); + config_release_config(); if (ret < 0) { fprintf(stderr, "FATAL: error parsing config file:"); switch (ret) { diff --git a/src/sighandler.c b/src/sighandler.c index 984beb0e..459fca76 100644 --- a/src/sighandler.c +++ b/src/sighandler.c @@ -10,6 +10,7 @@ #include "refbuf.h" #include "client.h" #include "logging.h" +#include "event.h" #include "sighandler.h" @@ -34,16 +35,22 @@ void sighandler_initialize(void) void _sig_hup(int signo) { - INFO1("Caught signal %d, rehashing config and reopening logfiles (unimplemented)...", signo); + /* We do this elsewhere because it's a bad idea to hang around for too + * long re-reading an entire config file inside a signal handler. Bad + * practice. + */ + + INFO1("Caught signal %d, scheduling config reread ...", + signo); /* reread config file */ - /* reopen logfiles */ + connection_inject_event(EVENT_CONFIG_READ, NULL); + + /* reopen logfiles (TODO: We don't do this currently) */ -#ifdef __linux__ - /* linux requires us to reattach the signal handler */ + /* some OSes require us to reattach the signal handler */ signal(SIGHUP, _sig_hup); -#endif } void _sig_die(int signo) diff --git a/src/slave.c b/src/slave.c index 599912a1..3ab63673 100644 --- a/src/slave.c +++ b/src/slave.c @@ -49,11 +49,18 @@ thread_type *_slave_thread_id; static int _initialized = 0; void slave_initialize(void) { + ice_config_t *config; if (_initialized) return; + + config = config_get_config(); /* Don't create a slave thread if it isn't configured */ - if (config_get_config()->master_server == NULL && - config_get_config()->relay == NULL) + if (config->master_server == NULL && + config->relay == NULL) + { + config_release_config(); return; + } + config_release_config(); _initialized = 1; _slave_thread_id = thread_create("Slave Thread", _slave_thread, NULL, THREAD_ATTACHED); @@ -131,28 +138,48 @@ static void create_relay_stream(char *server, int port, static void *_slave_thread(void *arg) { sock_t mastersock; char buf[256]; - int interval = config_get_config()->master_update_interval; + int interval; char *authheader, *data; int len; char *username = "relay"; - char *password = config_get_config()->master_password; + char *password; + int max_interval; relay_server *relay; + ice_config_t *config; + + config = config_get_config(); + + password = config->master_password; + interval = max_interval = config->master_update_interval; if(password == NULL) - password = config_get_config()->source_password; + password = config->source_password; + + config_release_config(); while (_initialized) { - if (config_get_config()->master_update_interval > ++interval) { + if (max_interval > ++interval) { thread_sleep(1000000); continue; } - else - interval = 0; + else { + /* In case it's been reconfigured */ + config = config_get_config(); + max_interval = config->master_update_interval; + config_release_config(); + + interval = 0; + } + + config = config_get_config(); + if(config->master_server != NULL) { + char *server = config->master_server; + int port = config->master_server_port; + config_release_config(); + + mastersock = sock_connect_wto(server, port, 0); - if(config_get_config()->master_server != NULL) { - mastersock = sock_connect_wto(config_get_config()->master_server, - config_get_config()->master_server_port, 0); if (mastersock == SOCK_ERROR) { WARN0("Relay slave failed to contact master server to fetch stream list"); continue; @@ -180,19 +207,23 @@ static void *_slave_thread(void *arg) { if (!source_find_mount(buf)) { avl_tree_unlock(global.source_tree); - create_relay_stream( - config_get_config()->master_server, - config_get_config()->master_server_port, - buf, NULL, 0); + create_relay_stream(server, port, buf, NULL, 0); } else avl_tree_unlock(global.source_tree); } sock_close(mastersock); } + else { + config_release_config(); + } /* And now, we process the individual mounts... */ - relay = config_get_config()->relay; + config = config_get_config(); + relay = config->relay; + thread_mutex_lock(&(config_locks()->relay_lock)); + config_release_config(); + while(relay) { avl_tree_rlock(global.source_tree); if(!source_find_mount(relay->localmount)) { @@ -205,6 +236,8 @@ static void *_slave_thread(void *arg) { avl_tree_unlock(global.source_tree); relay = relay->next; } + + thread_mutex_unlock(&(config_locks()->relay_lock)); } thread_exit(0); return NULL; diff --git a/src/source.c b/src/source.c index ad96bbb3..ea392275 100644 --- a/src/source.c +++ b/src/source.c @@ -59,7 +59,6 @@ source_t *source_create(client_t *client, connection_t *con, http_parser_t *parser, const char *mount, format_type_t type, mount_proxy *mountinfo) { - int i = 0; source_t *src; src = (source_t *)malloc(sizeof(source_t)); @@ -79,17 +78,6 @@ source_t *source_create(client_t *client, connection_t *con, 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]) { - src->ypdata[src->num_yp_directories] = yp_create_ypdata(); - src->ypdata[src->num_yp_directories]->yp_url = - config_get_config()->yp_url[i]; - src->ypdata[src->num_yp_directories]->yp_url_timeout = - config_get_config()->yp_url_timeout[i]; - src->ypdata[src->num_yp_directories]->yp_touch_interval = 0; - src->num_yp_directories++; - } - } if(mountinfo != NULL) { src->fallback_mount = mountinfo->fallback_mount; @@ -191,9 +179,31 @@ void *source_main(void *arg) int suppress_yp = 0; char *ai; - long queue_limit = config_get_config()->queue_size_limit; + long queue_limit; + ice_config_t *config; + char *hostname; + int port; - timeout = config_get_config()->source_timeout; + config = config_get_config(); + + queue_limit = config->queue_size_limit; + timeout = config->source_timeout; + hostname = config->hostname; + port = config->port; + + for (i=0;inum_yp_directories;i++) { + if (config->yp_url[i]) { + source->ypdata[source->num_yp_directories] = yp_create_ypdata(); + source->ypdata[source->num_yp_directories]->yp_url = + config->yp_url[i]; + source->ypdata[source->num_yp_directories]->yp_url_timeout = + config->yp_url_timeout[i]; + source->ypdata[source->num_yp_directories]->yp_touch_interval = 0; + source->num_yp_directories++; + } + } + + config_release_config(); /* grab a read lock, to make sure we get a chance to cleanup */ thread_rwlock_rlock(source->shutdown_rwlock); @@ -273,12 +283,11 @@ void *source_main(void *arg) } /* 6 for max size of port */ listen_url_size = strlen("http://") + - strlen(config_get_config()->hostname) + + strlen(hostname) + strlen(":") + 6 + strlen(source->mount) + 1; source->ypdata[i]->listen_url = malloc(listen_url_size); sprintf(source->ypdata[i]->listen_url, "http://%s:%d%s", - config_get_config()->hostname, config_get_config()->port, - source->mount); + hostname, port, source->mount); } if(!suppress_yp) { @@ -609,6 +618,9 @@ done: global.sources--; global_unlock(); + if(source->dumpfile) + fclose(source->dumpfile); + /* release our hold on the lock so the main thread can continue cleaning up */ thread_rwlock_unlock(source->shutdown_rwlock); @@ -616,9 +628,6 @@ 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/util.c b/src/util.c index 666fab2c..279d1bbc 100644 --- a/src/util.c +++ b/src/util.c @@ -74,8 +74,11 @@ int util_read_header(int sock, char *buff, unsigned long len) unsigned long pos; char c; ice_config_t *config; + int header_timeout; config = config_get_config(); + header_timeout = config->header_timeout; + config_release_config(); read_bytes = 1; pos = 0; @@ -84,7 +87,7 @@ int util_read_header(int sock, char *buff, unsigned long len) while ((read_bytes == 1) && (pos < (len - 1))) { read_bytes = 0; - if (util_timed_wait_for_fd(sock, config->header_timeout*1000) > 0) { + if (util_timed_wait_for_fd(sock, header_timeout*1000) > 0) { if ((read_bytes = recv(sock, &c, 1, 0))) { if (c != '\r') buff[pos++] = c; @@ -199,9 +202,14 @@ char *util_get_path_from_uri(char *uri) { char *util_get_path_from_normalised_uri(char *uri) { char *fullpath; + char *webroot; + ice_config_t *config = config_get_config(); - fullpath = malloc(strlen(uri) + strlen(config_get_config()->webroot_dir) + 1); - strcpy(fullpath, config_get_config()->webroot_dir); + webroot = config->webroot_dir; + config_release_config(); + + fullpath = malloc(strlen(uri) + strlen(webroot) + 1); + strcpy(fullpath, webroot); strcat(fullpath, uri); diff --git a/src/yp.c b/src/yp.c index 4b72c0b2..989a90c2 100644 --- a/src/yp.c +++ b/src/yp.c @@ -15,14 +15,18 @@ #define CATMODULE "yp" -int yp_submit_url(int curl_con, char *yp_url, char *url, char *type) +int yp_submit_url(int curl_con, char *yp_url, char *url, char *type, int i) { int ret = 0; + int *timeout; + ice_config_t *config = config_get_config(); + + timeout = config->yp_url_timeout + i; + config_release_config(); curl_easy_setopt(curl_get_handle(curl_con), CURLOPT_URL, yp_url); curl_easy_setopt(curl_get_handle(curl_con), CURLOPT_POSTFIELDS, url); - curl_easy_setopt(curl_get_handle(curl_con), CURLOPT_TIMEOUT, - config_get_config()->yp_url_timeout); + curl_easy_setopt(curl_get_handle(curl_con), CURLOPT_TIMEOUT, timeout); /* get it! */ memset(curl_get_result(curl_con), 0, sizeof(struct curl_memory_struct)); @@ -93,7 +97,7 @@ int yp_remove(source_t *source) else { /* specify URL to get */ ret = yp_submit_url(curl_con, source->ypdata[i]->yp_url, - url, "yp_remove"); + url, "yp_remove", i); } if (url) { free(url); @@ -159,7 +163,7 @@ int yp_touch(source_t *source) else { /* specify URL to get */ ret = yp_submit_url(curl_con, source->ypdata[i]->yp_url, - url, "yp_touch"); + url, "yp_touch", i); if (!ret) { source->ypdata[i]->sid[0] = 0; } @@ -291,7 +295,7 @@ int yp_add(source_t *source, int which) else { /* specify URL to get */ ret = yp_submit_url(curl_con, source->ypdata[i]->yp_url, - url, "yp_add"); + url, "yp_add", i); if (ret) { if (strlen(curl_get_header_result(curl_con)->sid) > 0) {