diff --git a/src/cfgfile.c b/src/cfgfile.c new file mode 100644 index 00000000..66af2f36 --- /dev/null +++ b/src/cfgfile.c @@ -0,0 +1,791 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "thread/thread.h" +#include "cfgfile.h" +#include "refbuf.h" +#include "client.h" +#include "logging.h" + +#define CATMODULE "CONFIG" +#define CONFIG_DEFAULT_LOCATION "Earth" +#define CONFIG_DEFAULT_ADMIN "icemaster@localhost" +#define CONFIG_DEFAULT_CLIENT_LIMIT 256 +#define CONFIG_DEFAULT_SOURCE_LIMIT 16 +#define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (100*1024) +#define CONFIG_DEFAULT_THREADPOOL_SIZE 4 +#define CONFIG_DEFAULT_CLIENT_TIMEOUT 30 +#define CONFIG_DEFAULT_HEADER_TIMEOUT 15 +#define CONFIG_DEFAULT_SOURCE_TIMEOUT 10 +#define CONFIG_DEFAULT_SOURCE_PASSWORD "changeme" +#define CONFIG_DEFAULT_RELAY_PASSWORD "changeme" +#define CONFIG_DEFAULT_ICE_LOGIN 0 +#define CONFIG_DEFAULT_FILESERVE 1 +#define CONFIG_DEFAULT_TOUCH_FREQ 5 +#define CONFIG_DEFAULT_HOSTNAME "localhost" +#define CONFIG_DEFAULT_ACCESS_LOG "access.log" +#define CONFIG_DEFAULT_ERROR_LOG "error.log" +#define CONFIG_DEFAULT_LOG_LEVEL 4 +#define CONFIG_DEFAULT_CHROOT 0 +#define CONFIG_DEFAULT_CHUID 0 +#define CONFIG_DEFAULT_USER NULL +#define CONFIG_DEFAULT_GROUP NULL +#define CONFIG_MASTER_UPDATE_INTERVAL 120 +#define CONFIG_YP_URL_TIMEOUT 10 + +#ifndef _WIN32 +#define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast" +#define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs" +#define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot" +#define CONFIG_DEFAULT_ADMINROOT_DIR "/usr/local/icecast/admin" +#else +#define CONFIG_DEFAULT_BASE_DIR ".\\" +#define CONFIG_DEFAULT_LOG_DIR ".\\logs" +#define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot" +#define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin" +#endif + +static ice_config_t _current_configuration; +static ice_config_locks _locks; + +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 _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *c); +static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); + +static void create_locks() { + thread_mutex_create(&_locks.relay_lock); + thread_mutex_create(&_locks.mounts_lock); + thread_mutex_create(&_locks.config_lock); +} + +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; + relay_server *relay, *nextrelay; + mount_proxy *mount, *nextmount; + aliases *alias, *nextalias; + int i; + + if (c->config_filename) + free(c->config_filename); + + if (c->location && c->location != CONFIG_DEFAULT_LOCATION) + xmlFree(c->location); + if (c->admin && c->admin != CONFIG_DEFAULT_ADMIN) + xmlFree(c->admin); + if (c->source_password && c->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD) + xmlFree(c->source_password); + if (c->admin_username) + xmlFree(c->admin_username); + if (c->admin_password) + xmlFree(c->admin_password); + if (c->hostname && c->hostname != CONFIG_DEFAULT_HOSTNAME) + xmlFree(c->hostname); + if (c->base_dir && c->base_dir != CONFIG_DEFAULT_BASE_DIR) + xmlFree(c->base_dir); + if (c->log_dir && c->log_dir != CONFIG_DEFAULT_LOG_DIR) + xmlFree(c->log_dir); + if (c->webroot_dir && c->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) + xmlFree(c->webroot_dir); + if (c->adminroot_dir && c->adminroot_dir != CONFIG_DEFAULT_ADMINROOT_DIR) + xmlFree(c->adminroot_dir); + if (c->access_log && c->access_log != CONFIG_DEFAULT_ACCESS_LOG) + xmlFree(c->access_log); + if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG) + xmlFree(c->error_log); + for(i=0; i < MAX_LISTEN_SOCKETS; i++) { + if (c->listeners[i].bind_address) xmlFree(c->listeners[i].bind_address); + } + if (c->master_server) xmlFree(c->master_server); + if (c->master_password) xmlFree(c->master_password); + if (c->user) xmlFree(c->user); + if (c->group) xmlFree(c->group); + + thread_mutex_lock(&(_locks.relay_lock)); + relay = c->relay; + while(relay) { + nextrelay = relay->next; + xmlFree(relay->server); + xmlFree(relay->mount); + if(relay->localmount) + xmlFree(relay->localmount); + free(relay); + relay = nextrelay; + } + thread_mutex_unlock(&(_locks.relay_lock)); + + thread_mutex_lock(&(_locks.mounts_lock)); + mount = c->mounts; + while(mount) { + nextmount = mount->next; + xmlFree(mount->mountname); + xmlFree(mount->username); + xmlFree(mount->password); + xmlFree(mount->dumpfile); + xmlFree(mount->fallback_mount); + free(mount); + mount = nextmount; + } + thread_mutex_unlock(&(_locks.mounts_lock)); + + alias = c->aliases; + while(alias) { + nextalias = alias->next; + xmlFree(alias->source); + xmlFree(alias->destination); + xmlFree(alias->bind_address); + free(alias); + alias = nextalias; + } + + dirnode = c->dir_list; + while(dirnode) { + nextdirnode = dirnode->next; + xmlFree(dirnode->host); + free(dirnode); + dirnode = nextdirnode; + } + + memset(c, 0, sizeof(ice_config_t)); +} + +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; + + xmlInitParser(); + doc = xmlParseFile(filename); + if (doc == NULL) { + return CONFIG_EPARSE; + } + + node = xmlDocGetRootElement(doc); + if (node == NULL) { + xmlFreeDoc(doc); + xmlCleanupParser(); + return CONFIG_ENOROOT; + } + + if (strcmp(node->name, "icecast") != 0) { + xmlFreeDoc(doc); + xmlCleanupParser(); + return CONFIG_EBADROOT; + } + + config_init_configuration(configuration); + + configuration->config_filename = (char *)strdup(filename); + + _parse_root(doc, node->xmlChildrenNode, configuration); + + xmlFreeDoc(doc); + + return 0; +} + +int config_parse_cmdline(int arg, char **argv) +{ + return 0; +} + +ice_config_locks *config_locks(void) +{ + return &_locks; +} + +void config_release_config(void) +{ + thread_mutex_unlock(&(_locks.config_lock)); +} + +ice_config_t *config_get_config(void) +{ + thread_mutex_lock(&(_locks.config_lock)); + return &_current_configuration; +} + +/* 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) +{ + return &_current_configuration; +} + +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->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 = 0; + configuration->listeners[0].port = 0; + configuration->listeners[0].bind_address = NULL; + configuration->master_server = NULL; + configuration->master_server_port = 0; + 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->adminroot_dir = CONFIG_DEFAULT_ADMINROOT_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; + + do { + if (node == NULL) break; + 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); + } 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); + } else if(strcmp(node->name, "authentication") == 0) { + _parse_authentication(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "source-password") == 0) { + /* TODO: This is the backwards-compatibility location */ + char *mount, *pass; + if ((mount = (char *)xmlGetProp(node, "mount")) != NULL) { + pass = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + /* 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); + } + } else if (strcmp(node->name, "icelogin") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + 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); + 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); + } else if (strcmp(node->name, "listen-socket") == 0) { + _parse_listen_socket(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "port") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + configuration->port = atoi(tmp); + configuration->listeners[0].port = atoi(tmp); + if (tmp) xmlFree(tmp); + } else if (strcmp(node->name, "bind-address") == 0) { + if (configuration->listeners[0].bind_address) + xmlFree(configuration->listeners[0].bind_address); + configuration->listeners[0].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); + } 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); + } else if (strcmp(node->name, "master-server-port") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + 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); + } else if (strcmp(node->name, "limits") == 0) { + _parse_limits(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "relay") == 0) { + _parse_relay(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "mount") == 0) { + _parse_mount(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "directory") == 0) { + _parse_directory(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "paths") == 0) { + _parse_paths(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "logging") == 0) { + _parse_logging(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "security") == 0) { + _parse_security(doc, node->xmlChildrenNode, configuration); + } + } while ((node = node->next)); +} + +static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) +{ + char *tmp; + + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "clients") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + 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); + 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); + if (tmp) xmlFree(tmp); + } else if (strcmp(node->name, "threadpool") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + 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); + if (tmp) xmlFree(tmp); + } else if (strcmp(node->name, "header-timeout") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + 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); + if (tmp) xmlFree(tmp); + } + } while ((node = node->next)); +} + +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 *last=NULL; + + while(current) { + last = current; + current = current->next; + } + + if(last) + last->next = mount; + else + configuration->mounts = mount; + + mount->max_listeners = -1; + mount->next = NULL; + + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "mount-name") == 0) { + mount->mountname = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "username") == 0) { + mount->username = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "password") == 0) { + mount->password = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "dump-file") == 0) { + mount->dumpfile = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "fallback-mount") == 0) { + mount->fallback_mount = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "max-listeners") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + mount->max_listeners = atoi(tmp); + if(tmp) xmlFree(tmp); + } + } while ((node = node->next)); +} + +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 *last=NULL; + + while(current) { + last = current; + current = current->next; + } + + if(last) + last->next = relay; + else + configuration->relay = relay; + + relay->next = NULL; + + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "server") == 0) { + relay->server = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "port") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + relay->port = atoi(tmp); + if(tmp) xmlFree(tmp); + } + else if (strcmp(node->name, "mount") == 0) { + relay->mount = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "local-mount") == 0) { + relay->localmount = (char *)xmlNodeListGetString( + doc, node->xmlChildrenNode, 1); + } + else if (strcmp(node->name, "relay-shoutcast-metadata") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + relay->mp3metadata = atoi(tmp); + if(tmp) xmlFree(tmp); + } + } while ((node = node->next)); +} + +static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) +{ + listener_t *listener = NULL; + int i; + char *tmp; + + for(i=0; i < MAX_LISTEN_SOCKETS; i++) { + if(configuration->listeners[i].port <= 0) { + listener = &(configuration->listeners[i]); + break; + } + } + + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "port") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if(configuration->port == 0) + configuration->port = atoi(tmp); + listener->port = atoi(tmp); + if(tmp) xmlFree(tmp); + } + else if (strcmp(node->name, "bind-address") == 0) { + listener->bind_address = (char *)xmlNodeListGetString(doc, + node->xmlChildrenNode, 1); + } + } while ((node = node->next)); +} + +static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) +{ + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "source-password") == 0) { + char *mount, *pass; + if ((mount = (char *)xmlGetProp(node, "mount")) != NULL) { + pass = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + /* 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); + } + } else if (strcmp(node->name, "admin-password") == 0) { + 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 = + (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + } + } while ((node = node->next)); +} + +static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) +{ + char *tmp; + + if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) { + ERROR0("Maximum number of yp directories exceeded!"); + return; + } + do { + if (node == NULL) break; + 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] = + (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] = + atoi(tmp); + } else if (strcmp(node->name, "server") == 0) { + _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); + if (tmp) xmlFree(tmp); + } + } while ((node = node->next)); + configuration->num_yp_directories++; +} + +static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) +{ + char *temp; + aliases *alias, *current, *last; + + 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); + } 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); + } 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; + } else if (strcmp(node->name, "adminroot") == 0) { + if (configuration->adminroot_dir && configuration->adminroot_dir != CONFIG_DEFAULT_ADMINROOT_DIR) + xmlFree(configuration->adminroot_dir); + configuration->adminroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/') + configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0; + } else if (strcmp(node->name, "alias") == 0) { + alias = malloc(sizeof(aliases)); + alias->next = NULL; + alias->source = xmlGetProp(node, "source"); + if(alias->source == NULL) { + free(alias); + continue; + } + alias->destination = xmlGetProp(node, "dest"); + if(alias->destination == NULL) { + xmlFree(alias->source); + free(alias); + continue; + } + temp = NULL; + temp = xmlGetProp(node, "port"); + if(temp != NULL) { + alias->port = atoi(temp); + xmlFree(temp); + } + else + alias->port = -1; + alias->bind_address = xmlGetProp(node, "bind-address"); + current = configuration->aliases; + last = NULL; + while(current) { + last = current; + current = current->next; + } + if(last) + last->next = alias; + else + configuration->aliases = alias; + } + } while ((node = node->next)); +} + +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); + } 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); + } else if (strcmp(node->name, "loglevel") == 0) { + char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + configuration->loglevel = atoi(tmp); + if (tmp) xmlFree(tmp); + } + } while ((node = node->next)); +} + +static void _parse_security(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) +{ + char *tmp; + xmlNodePtr oldnode; + + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "chroot") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + configuration->chroot = atoi(tmp); + if (tmp) xmlFree(tmp); + } else if (strcmp(node->name, "changeowner") == 0) { + 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); + } else if(strcmp(node->name, "group") == 0) { + if(configuration->group) xmlFree(configuration->group); + configuration->group = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + } + } while((node = node->next)); + node = oldnode; + } + } while ((node = node->next)); +} + +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->host = NULL; + addnode = 0; + + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "host") == 0) { + server->host = (char *)xmlNodeListGetString(doc, + node->xmlChildrenNode, 1); + addnode = 1; + } else if (strcmp(node->name, "touch-interval") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + server->touch_interval = atoi(tmp); + if (tmp) xmlFree(tmp); + } + server->next = NULL; + } while ((node = node->next)); + + if (addnode) { + dirnode = configuration->dir_list; + if (dirnode == NULL) { + configuration->dir_list = server; + } else { + while (dirnode->next) dirnode = dirnode->next; + + dirnode->next = server; + } + + server = NULL; + addnode = 0; + } + +} + + diff --git a/src/cfgfile.h b/src/cfgfile.h new file mode 100644 index 00000000..c7eeea74 --- /dev/null +++ b/src/cfgfile.h @@ -0,0 +1,144 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#define CONFIG_EINSANE -1 +#define CONFIG_ENOROOT -2 +#define CONFIG_EBADROOT -3 +#define CONFIG_EPARSE -4 + +#define MAX_YP_DIRECTORIES 25 + + +#include "thread/thread.h" +#include "avl/avl.h" +#include "global.h" + +typedef struct ice_config_dir_tag +{ + char *host; + int touch_interval; + struct ice_config_dir_tag *next; +} ice_config_dir_t; + +typedef struct _relay_server { + char *server; + int port; + char *mount; + char *localmount; + int mp3metadata; + struct _relay_server *next; +} relay_server; + +typedef struct _mount_proxy { + char *mountname; /* The mountpoint this proxy is used for */ + + char *username; /* Username and password for this mountpoint. If unset, */ + char *password; /* falls back to global source password */ + + char *dumpfile; /* Filename to dump this stream to (will be appended). NULL + to not dump. */ + int max_listeners; /* Max listeners for this mountpoint only. -1 to not + limit here (i.e. only use the global limit) */ + char *fallback_mount; + struct _mount_proxy *next; +} mount_proxy; + +typedef struct _aliases { + char *source; + char *destination; + int port; + char *bind_address; + struct _aliases *next; +}aliases; + +typedef struct { + int port; + char *bind_address; +} listener_t; + +typedef struct ice_config_tag +{ + char *config_filename; + + char *location; + char *admin; + + int client_limit; + int source_limit; + long queue_size_limit; + int threadpool_size; + int client_timeout; + int header_timeout; + int source_timeout; + int ice_login; + int fileserve; + + char *source_password; + char *admin_username; + char *admin_password; + + int touch_interval; + ice_config_dir_t *dir_list; + + char *hostname; + int port; + + listener_t listeners[MAX_LISTEN_SOCKETS]; + + char *master_server; + int master_server_port; + int master_update_interval; + char *master_password; + + relay_server *relay; + + mount_proxy *mounts; + + char *base_dir; + char *log_dir; + char *webroot_dir; + char *adminroot_dir; + aliases *aliases; + + char *access_log; + char *error_log; + int loglevel; + + int chroot; + int chuid; + char *user; + char *group; + char *yp_url[MAX_YP_DIRECTORIES]; + int yp_url_timeout[MAX_YP_DIRECTORIES]; + 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, 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__ */ + + +