cfgfile.c 58.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
 * Copyright 2000-2004, Jack Moffitt <jack@xiph.org, 
 *                      Michael Smith <msmith@xiph.org>,
 *                      oddsock <oddsock@xiph.org>,
 *                      Karl Heyes <karl@xiph.org>
 *                      and others (see AUTHORS for details).
11
 * Copyright 2011,      Thomas B. "dm8tbr" Ruecker <thomas.ruecker@tieto.com>,
12
 *                      Dave 'justdave' Miller <justdave@mozilla.com>.
13
 * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
14 15
 */

16 17 18 19 20 21 22
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
23
#ifndef _WIN32
24
#include <fnmatch.h>
25
#endif
26 27 28 29 30 31 32 33 34 35 36 37 38 39
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#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
40
#define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (500*1024)
41
#define CONFIG_DEFAULT_BURST_SIZE (64*1024)
42 43 44 45
#define CONFIG_DEFAULT_THREADPOOL_SIZE 4
#define CONFIG_DEFAULT_CLIENT_TIMEOUT 30
#define CONFIG_DEFAULT_HEADER_TIMEOUT 15
#define CONFIG_DEFAULT_SOURCE_TIMEOUT 10
46
#define CONFIG_DEFAULT_MASTER_USERNAME "relay"
47
#define CONFIG_DEFAULT_SHOUTCAST_MOUNT "/stream"
48 49 50 51
#define CONFIG_DEFAULT_ICE_LOGIN 0
#define CONFIG_DEFAULT_FILESERVE 1
#define CONFIG_DEFAULT_TOUCH_FREQ 5
#define CONFIG_DEFAULT_HOSTNAME "localhost"
52
#define CONFIG_DEFAULT_PLAYLIST_LOG NULL
53 54
#define CONFIG_DEFAULT_ACCESS_LOG "access.log"
#define CONFIG_DEFAULT_ERROR_LOG "error.log"
55
#define CONFIG_DEFAULT_LOG_LEVEL 3
56 57 58 59 60 61
#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
62
#define CONFIG_DEFAULT_CIPHER_LIST "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS"
63 64 65 66 67 68

#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"
69
#define MIMETYPESFILE "/etc/mime.types"
70 71 72 73 74
#else
#define CONFIG_DEFAULT_BASE_DIR ".\\"
#define CONFIG_DEFAULT_LOG_DIR ".\\logs"
#define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot"
#define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin"
75
#define MIMETYPESFILE ".\\mime.types"
76 77 78 79 80 81 82 83 84 85 86 87 88 89
#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);
90 91
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node,
        ice_config_http_header_t **http_headers);
92 93 94 95 96 97
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);

98 99 100
static void merge_mounts(mount_proxy * dst, mount_proxy * src);
static inline void _merge_mounts_all(ice_config_t *c);

101
static void create_locks(void) {
102
    thread_mutex_create(&_locks.relay_lock);
103
    thread_rwlock_create(&_locks.config_lock);
104 105
}

106
static void release_locks(void) {
107
    thread_mutex_destroy(&_locks.relay_lock);
108
    thread_rwlock_destroy(&_locks.config_lock);
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
}

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);
}

128 129 130 131 132 133 134 135 136 137 138 139
static void config_clear_http_header(ice_config_http_header_t *header) {
 ice_config_http_header_t *old;

 while (header) {
  xmlFree(header->name);
  xmlFree(header->value);
  old = header;
  header = header->next;
  free(old);
 }
}

140
static inline ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) {
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    ice_config_http_header_t *ret = NULL;
    ice_config_http_header_t *cur = NULL;
    ice_config_http_header_t *old = NULL;

    while (header) {
        if (cur) {
            cur->next = calloc(1, sizeof(ice_config_http_header_t));
            old = cur;
            cur = cur->next;
        } else {
            ret = calloc(1, sizeof(ice_config_http_header_t));
            cur = ret;
        }

        if (!cur) return ret; /* TODO: do better error handling */

157 158 159 160
        cur->type   = header->type;
        cur->name   = (char *)xmlCharStrdup(header->name);
        cur->value  = (char *)xmlCharStrdup(header->value);
        cur->status = header->status;
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

        if (!cur->name || !cur->value) {
            if (cur->name) xmlFree(cur->name);
            if (cur->value) xmlFree(cur->value);
            if (old) {
                old->next = NULL;
            } else {
                ret = NULL;
            }
            free(cur);
            return ret;
        }

        header = header->next;
    }

    return ret;
}

180 181 182 183
static void config_clear_mount (mount_proxy *mount)
{
    config_options_t *option;

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    if (mount->mountname)       xmlFree (mount->mountname);
    if (mount->username)        xmlFree (mount->username);
    if (mount->password)        xmlFree (mount->password);
    if (mount->dumpfile)        xmlFree (mount->dumpfile);
    if (mount->intro_filename)  xmlFree (mount->intro_filename);
    if (mount->on_connect)      xmlFree (mount->on_connect);
    if (mount->on_disconnect)   xmlFree (mount->on_disconnect);
    if (mount->fallback_mount)  xmlFree (mount->fallback_mount);
    if (mount->stream_name)     xmlFree (mount->stream_name);
    if (mount->stream_description)  xmlFree (mount->stream_description);
    if (mount->stream_url)      xmlFree (mount->stream_url);
    if (mount->stream_genre)    xmlFree (mount->stream_genre);
    if (mount->bitrate)         xmlFree (mount->bitrate);
    if (mount->type)            xmlFree (mount->type);
    if (mount->charset)         xmlFree (mount->charset);
    if (mount->cluster_password)    xmlFree (mount->cluster_password);

    if (mount->auth_type)       xmlFree (mount->auth_type);
202 203 204 205
    option = mount->auth_options;
    while (option)
    {
        config_options_t *nextopt = option->next;
206 207
        if (option->name)   xmlFree (option->name);
        if (option->value)  xmlFree (option->value);
208 209 210 211
        free (option);
        option = nextopt;
    }
    auth_release (mount->auth);
212
    config_clear_http_header(mount->http_headers);
213 214 215
    free (mount);
}

216 217 218 219 220 221 222
listener_t *config_clear_listener (listener_t *listener)
{
    listener_t *next = NULL;
    if (listener)
    {
        next = listener->next;
        if (listener->bind_address)     xmlFree (listener->bind_address);
223
        if (listener->shoutcast_mount)  xmlFree (listener->shoutcast_mount);
224 225 226 227
        free (listener);
    }
    return next;
}
228

229 230 231 232 233 234 235 236
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;

237
    free(c->config_filename);
238

Karl Heyes's avatar
Karl Heyes committed
239
    xmlFree (c->server_id);
240 241 242
    if (c->location) xmlFree(c->location);
    if (c->admin) xmlFree(c->admin);
    if (c->source_password) xmlFree(c->source_password);
243 244 245 246
    if (c->admin_username)
        xmlFree(c->admin_username);
    if (c->admin_password)
        xmlFree(c->admin_password);
247 248 249 250
    if (c->relay_username)
        xmlFree(c->relay_username);
    if (c->relay_password)
        xmlFree(c->relay_password);
251 252 253 254 255
    if (c->hostname) xmlFree(c->hostname);
    if (c->base_dir) xmlFree(c->base_dir);
    if (c->log_dir) xmlFree(c->log_dir);
    if (c->webroot_dir) xmlFree(c->webroot_dir);
    if (c->adminroot_dir) xmlFree(c->adminroot_dir);
Karl Heyes's avatar
Karl Heyes committed
256
    if (c->cert_file) xmlFree(c->cert_file);
257
    if (c->cipher_list) xmlFree(c->cipher_list);
Karl Heyes's avatar
Karl Heyes committed
258
    if (c->pidfile)
259
        xmlFree(c->pidfile);
260 261
    if (c->banfile) xmlFree(c->banfile);
    if (c->allowfile) xmlFree(c->allowfile);
262 263 264 265
    if (c->playlist_log) xmlFree(c->playlist_log);
    if (c->access_log) xmlFree(c->access_log);
    if (c->error_log) xmlFree(c->error_log);
    if (c->shoutcast_mount) xmlFree(c->shoutcast_mount);
266
    if (c->master_server) xmlFree(c->master_server);
267
    if (c->master_username) xmlFree(c->master_username);
268 269 270
    if (c->master_password) xmlFree(c->master_password);
    if (c->user) xmlFree(c->user);
    if (c->group) xmlFree(c->group);
271
    if (c->mimetypes_fn) xmlFree (c->mimetypes_fn);
272

273 274 275
    while ((c->listen_sock = config_clear_listener (c->listen_sock)))
        ;

276 277 278 279 280 281
    thread_mutex_lock(&(_locks.relay_lock));
    relay = c->relay;
    while(relay) {
        nextrelay = relay->next;
        xmlFree(relay->server);
        xmlFree(relay->mount);
Karl Heyes's avatar
Karl Heyes committed
282
        xmlFree(relay->localmount);
283 284 285 286 287 288 289 290
        free(relay);
        relay = nextrelay;
    }
    thread_mutex_unlock(&(_locks.relay_lock));

    mount = c->mounts;
    while(mount) {
        nextmount = mount->next;
291
        config_clear_mount (mount);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
        mount = nextmount;
    }

    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;
    }
312
#ifdef USE_YP
Karl Heyes's avatar
Karl Heyes committed
313
    i = 0;
314
    while (i < c->num_yp_directories)
Karl Heyes's avatar
Karl Heyes committed
315 316 317 318 319
    {
        xmlFree (c->yp_url[i]);
        i++;
    }
#endif
320

321 322
    config_clear_http_header(c->http_headers);

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
    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;
    
    doc = xmlParseFile(filename);
    if (doc == NULL) {
        return CONFIG_EPARSE;
    }

    node = xmlDocGetRootElement(doc);
    if (node == NULL) {
        xmlFreeDoc(doc);
        return CONFIG_ENOROOT;
    }

350
    if (xmlStrcmp (node->name, XMLSTR("icecast")) != 0) {
351 352 353 354 355 356
        xmlFreeDoc(doc);
        return CONFIG_EBADROOT;
    }

    config_init_configuration(configuration);

357
    configuration->config_filename = strdup (filename);
358 359 360 361 362

    _parse_root(doc, node->xmlChildrenNode, configuration);

    xmlFreeDoc(doc);

363 364
    _merge_mounts_all(configuration);

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    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)
{
380
    thread_rwlock_unlock(&(_locks.config_lock));
381 382 383 384
}

ice_config_t *config_get_config(void)
{
385 386 387 388 389 390 391
    thread_rwlock_rlock(&(_locks.config_lock));
    return &_current_configuration;
}

ice_config_t *config_grab_config(void)
{
    thread_rwlock_wlock(&(_locks.config_lock));
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    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)
{
407
    configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
408
    configuration->server_id = (char *)xmlCharStrdup (ICECAST_VERSION_STRING);
409
    configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN);
410 411 412 413 414 415 416
    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;
417
    configuration->source_password = NULL;
418
    configuration->shoutcast_mount = (char *)xmlCharStrdup (CONFIG_DEFAULT_SHOUTCAST_MOUNT);
419 420 421
    configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
    configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
    configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
422
    configuration->on_demand = 0;
423
    configuration->dir_list = NULL;
424 425
    configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
    configuration->mimetypes_fn = (char *)xmlCharStrdup (MIMETYPESFILE);
426 427 428
    configuration->master_server = NULL;
    configuration->master_server_port = 0;
    configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
429
    configuration->master_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
430
    configuration->master_password = NULL;
431 432
    configuration->base_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_BASE_DIR);
    configuration->log_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOG_DIR);
433
    configuration->cipher_list = (char *)xmlCharStrdup (CONFIG_DEFAULT_CIPHER_LIST);
434 435 436 437 438
    configuration->webroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_WEBROOT_DIR);
    configuration->adminroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMINROOT_DIR);
    configuration->playlist_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_PLAYLIST_LOG);
    configuration->access_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ACCESS_LOG);
    configuration->error_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ERROR_LOG);
439 440 441
    configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
    configuration->chroot = CONFIG_DEFAULT_CHROOT;
    configuration->chuid = CONFIG_DEFAULT_CHUID;
442 443
    configuration->user = NULL;
    configuration->group = NULL;
444
    configuration->num_yp_directories = 0;
445
    configuration->relay_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
446
    configuration->relay_password = NULL;
447
    /* default to a typical prebuffer size used by clients */
448
    configuration->burst_size = CONFIG_DEFAULT_BURST_SIZE;
449 450 451 452 453 454 455
}

static void _parse_root(xmlDocPtr doc, xmlNodePtr node, 
        ice_config_t *configuration)
{
    char *tmp;

456 457 458 459
    configuration->listen_sock = calloc (1, sizeof (*configuration->listen_sock));
    configuration->listen_sock->port = 8000;
    configuration->listen_sock_count = 1;

460 461 462 463
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

464
        if (xmlStrcmp (node->name, XMLSTR("location")) == 0) {
465
            if (configuration->location) xmlFree(configuration->location);
466
            configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
467
        } else if (xmlStrcmp (node->name, XMLSTR("admin")) == 0) {
468
            if (configuration->admin) xmlFree(configuration->admin);
469
            configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
470
        } else if (xmlStrcmp (node->name, XMLSTR("server-id")) == 0) {
471 472
            xmlFree (configuration->server_id);
            configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
473
            ICECAST_LOG_WARN("Warning, server version string override detected. This may lead to unexpected client software behavior.");
474
        } else if(xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
475
            _parse_authentication(doc, node->xmlChildrenNode, configuration);
476
        } else if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
477
            /* TODO: This is the backwards-compatibility location */
478
            ICECAST_LOG_WARN("<source-password> defined outside <authentication>. This is deprecated.");
479 480
            if (configuration->source_password) xmlFree(configuration->source_password);
            configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
481
        } else if (xmlStrcmp (node->name, XMLSTR("icelogin")) == 0) {
482 483 484
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->ice_login = atoi(tmp);
            if (tmp) xmlFree(tmp);
485
        } else if (xmlStrcmp (node->name, XMLSTR("fileserve")) == 0) {
486 487 488
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->fileserve = atoi(tmp);
            if (tmp) xmlFree(tmp);
489
        } else if (xmlStrcmp (node->name, XMLSTR("relays-on-demand")) == 0) {
490 491 492
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->on_demand = atoi(tmp);
            if (tmp) xmlFree(tmp);
493
        } else if (xmlStrcmp (node->name, XMLSTR("hostname")) == 0) {
494
            if (configuration->hostname) xmlFree(configuration->hostname);
495
            configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
496
        } else if (xmlStrcmp (node->name, XMLSTR("mime-types")) == 0) {
497 498
            if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn);
            configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
499
        } else if (xmlStrcmp (node->name, XMLSTR("listen-socket")) == 0) {
500
            _parse_listen_socket(doc, node->xmlChildrenNode, configuration);
501
        } else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
502
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
503 504 505 506 507 508 509
            if (tmp) {
                configuration->port = atoi(tmp);
                configuration->listen_sock->port = atoi(tmp);
                xmlFree(tmp);
            } else {
                ICECAST_LOG_WARN("<port> must not be empty.");
            }
510
        } else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
511 512 513
            if (configuration->listen_sock->bind_address) 
                xmlFree(configuration->listen_sock->bind_address);
            configuration->listen_sock->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
514
        } else if (xmlStrcmp (node->name, XMLSTR("master-server")) == 0) {
515 516
            if (configuration->master_server) xmlFree(configuration->master_server);
            configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
517
        } else if (xmlStrcmp (node->name, XMLSTR("master-username")) == 0) {
518 519
            if (configuration->master_username) xmlFree(configuration->master_username);
            configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
520
        } else if (xmlStrcmp (node->name, XMLSTR("master-password")) == 0) {
521 522
            if (configuration->master_password) xmlFree(configuration->master_password);
            configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
523
        } else if (xmlStrcmp (node->name, XMLSTR("master-server-port")) == 0) {
524 525
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->master_server_port = atoi(tmp);
526
            xmlFree (tmp);
527
        } else if (xmlStrcmp (node->name, XMLSTR("master-update-interval")) == 0) {
528 529
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->master_update_interval = atoi(tmp);
530
            xmlFree (tmp);
531
        } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
532
            if (configuration->shoutcast_mount) xmlFree(configuration->shoutcast_mount);
533
            configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
534
        } else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
535
            _parse_limits(doc, node->xmlChildrenNode, configuration);
536
        } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
537
            _parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers));
538
        } else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
539
            _parse_relay(doc, node->xmlChildrenNode, configuration);
540
        } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
541
            _parse_mount(doc, node, configuration);
542
        } else if (xmlStrcmp (node->name, XMLSTR("directory")) == 0) {
543
            _parse_directory(doc, node->xmlChildrenNode, configuration);
544
        } else if (xmlStrcmp (node->name, XMLSTR("paths")) == 0) {
545
            _parse_paths(doc, node->xmlChildrenNode, configuration);
546
        } else if (xmlStrcmp (node->name, XMLSTR("logging")) == 0) {
547
            _parse_logging(doc, node->xmlChildrenNode, configuration);
548
        } else if (xmlStrcmp (node->name, XMLSTR("security")) == 0) {
549 550 551
            _parse_security(doc, node->xmlChildrenNode, configuration);
        }
    } while ((node = node->next));
552 553 554 555 556 557 558 559

    /* drop the first listening socket details if more than one is defined, as we only
     * have port or listen-socket not both */
    if (configuration->listen_sock_count > 1)
    {
        configuration->listen_sock = config_clear_listener (configuration->listen_sock);
        configuration->listen_sock_count--;
    }
560 561
    if (configuration->port == 0)
        configuration->port = 8000;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583

   /* issue some warnings on bad configurations */
   if (!configuration->fileserve)
       ICECAST_LOG_WARN("Warning, serving of static files has been disabled in the config, this will also affect files used by the web interface (stylesheets, images).");

  if (!configuration->hostname || strcmp(configuration->hostname, CONFIG_DEFAULT_HOSTNAME) == 0) {
      ICECAST_LOG_WARN("Warning, <hostname> not configured, using default value \"%s\". This will cause problems, e.g. with YP directory listings.", CONFIG_DEFAULT_HOSTNAME);
      if (!configuration->hostname)
          configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
  }

  if (!configuration->location || strcmp(configuration->location, CONFIG_DEFAULT_LOCATION) == 0) {
      ICECAST_LOG_WARN("Warning, <location> not configured, using default value \"%s\".", CONFIG_DEFAULT_LOCATION);
      if (!configuration->location)
          configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
  }

  if (!configuration->admin || strcmp(configuration->admin, CONFIG_DEFAULT_ADMIN) == 0) {
      ICECAST_LOG_WARN("Warning, <admin> contact not configured, using default value \"%s\".", CONFIG_DEFAULT_ADMIN);
      if (!configuration->admin)
          configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN);
  }
584 585 586 587 588 589 590 591 592 593 594
}

static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, 
        ice_config_t *configuration)
{
    char *tmp;

    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

595
        if (xmlStrcmp (node->name, XMLSTR("clients")) == 0) {
596 597 598
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->client_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
599
        } else if (xmlStrcmp (node->name, XMLSTR("sources")) == 0) {
600 601 602
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->source_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
603
        } else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
604 605 606
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->queue_size_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
607
        } else if (xmlStrcmp (node->name, XMLSTR("threadpool")) == 0) {
608 609 610
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->threadpool_size = atoi(tmp);
            if (tmp) xmlFree(tmp);
611
        } else if (xmlStrcmp (node->name, XMLSTR("client-timeout")) == 0) {
612 613 614
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->client_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
615
        } else if (xmlStrcmp (node->name, XMLSTR("header-timeout")) == 0) {
616 617 618
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->header_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
619
        } else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
620 621 622
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->source_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
623
        } else if (xmlStrcmp (node->name, XMLSTR("burst-on-connect")) == 0) {
624
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
625 626 627
            if (atoi(tmp) == 0)
                configuration->burst_size = 0;
            if (tmp) xmlFree(tmp);
628
        } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
629 630
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->burst_size = atoi(tmp);
631
            if (tmp) xmlFree(tmp);
632 633 634 635 636 637 638 639 640 641 642 643
        }
    } 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;
    
644
    /* default <mount> settings */
645
    mount->mounttype = MOUNT_TYPE_NORMAL;
646
    mount->max_listeners = -1;
647
    mount->burst_size = -1;
648
    mount->mp3_meta_interval = -1;
649
    mount->yp_public = -1;
650 651
    mount->next = NULL;

652 653 654 655 656 657 658 659 660
    tmp = (char *)xmlGetProp(node, XMLSTR("type"));
    if (tmp) {
        if (strcmp(tmp, "normal") == 0) {
	    mount->mounttype = MOUNT_TYPE_NORMAL;
	}
	else if (strcmp(tmp, "default") == 0) {
	    mount->mounttype = MOUNT_TYPE_DEFAULT;
	}
	else {
661
	    ICECAST_LOG_WARN("Unknown mountpoint type: %s", tmp);
662 663 664
            config_clear_mount (mount);
            return;
	}
665
	xmlFree(tmp);
666 667 668 669
    }

    node = node->xmlChildrenNode;

670 671 672 673
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

674 675
        if (xmlStrcmp (node->name, XMLSTR("mount-name")) == 0) {
            mount->mountname = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
676
        }
677
        else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
678 679 680
            mount->username = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
681
        else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
682 683 684
            mount->password = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
685
        else if (xmlStrcmp (node->name, XMLSTR("dump-file")) == 0) {
686 687
            mount->dumpfile = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
688
        }
689
        else if (xmlStrcmp (node->name, XMLSTR("intro")) == 0) {
690 691
            mount->intro_filename = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
692
        }
693
        else if (xmlStrcmp (node->name, XMLSTR("fallback-mount")) == 0) {
694 695 696
            mount->fallback_mount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
697
        else if (xmlStrcmp (node->name, XMLSTR("fallback-when-full")) == 0) {
698 699 700 701
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->fallback_when_full = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
702
        else if (xmlStrcmp (node->name, XMLSTR("max-listeners")) == 0) {
703 704 705 706
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->max_listeners = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
707
        else if (xmlStrcmp (node->name, XMLSTR("charset")) == 0) {
708 709 710
            mount->charset = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
711
        else if (xmlStrcmp (node->name, XMLSTR("mp3-metadata-interval")) == 0) {
712 713 714 715
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->mp3_meta_interval = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
716
        else if (xmlStrcmp (node->name, XMLSTR("fallback-override")) == 0) {
717 718 719 720
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->fallback_override = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
721
        else if (xmlStrcmp (node->name, XMLSTR("no-mount")) == 0) {
722 723 724 725
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->no_mount = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
726
        else if (xmlStrcmp (node->name, XMLSTR("no-yp")) == 0) {
727
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
728
            mount->yp_public = atoi(tmp) == 0 ? -1 : 0;
729 730
            if(tmp) xmlFree(tmp);
        }
731
        else if (xmlStrcmp (node->name, XMLSTR("hidden")) == 0) {
732 733 734 735
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->hidden = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
736
        else if (xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
737
            mount->auth = auth_get_authenticator (node);
738
        }
739
        else if (xmlStrcmp (node->name, XMLSTR("on-connect")) == 0) {
740 741 742
            mount->on_connect = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
743
        else if (xmlStrcmp (node->name, XMLSTR("on-disconnect")) == 0) {
744 745 746
            mount->on_disconnect = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
747
        else if (xmlStrcmp (node->name, XMLSTR("max-listener-duration")) == 0) {
748 749 750 751
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->max_listener_duration = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
752
        else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
753 754 755 756
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->queue_size_limit = atoi (tmp);
            if(tmp) xmlFree(tmp);
        }
757
        else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
758 759 760 761 762 763
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            if (tmp)
            {
                mount->source_timeout = atoi (tmp);
                xmlFree(tmp);
            }
764
        } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
765 766 767
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->burst_size = atoi(tmp);
            if (tmp) xmlFree(tmp);
768
        } else if (xmlStrcmp (node->name, XMLSTR("cluster-password")) == 0) {
769 770
            mount->cluster_password = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
771
        } else if (xmlStrcmp (node->name, XMLSTR("stream-name")) == 0) {
772 773
            mount->stream_name = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
774
        } else if (xmlStrcmp (node->name, XMLSTR("stream-description")) == 0) {
775 776
            mount->stream_description = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
777
        } else if (xmlStrcmp (node->name, XMLSTR("stream-url")) == 0) {
778 779
            mount->stream_url = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
780
        } else if (xmlStrcmp (node->name, XMLSTR("genre")) == 0) {
781 782
            mount->stream_genre = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
783
        } else if (xmlStrcmp (node->name, XMLSTR("bitrate")) == 0) {
784 785
            mount->bitrate = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
786
        } else if (xmlStrcmp (node->name, XMLSTR("public")) == 0) {
787 788 789
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->yp_public = atoi (tmp);
            if(tmp) xmlFree(tmp);
790
        } else if (xmlStrcmp (node->name, XMLSTR("type")) == 0) {
791 792
            mount->type = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
793
        } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
794 795
            mount->subtype = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
796 797
        } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
            _parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers));
798
        }
799
    } while ((node = node->next));
800 801

    /* make sure we have at least the mountpoint name */
802
    if (mount->mountname == NULL && mount->mounttype != MOUNT_TYPE_DEFAULT)
803 804 805 806
    {
        config_clear_mount (mount);
        return;
    }
807 808
    else if (mount->mountname != NULL && mount->mounttype == MOUNT_TYPE_DEFAULT)
    {
809
    	ICECAST_LOG_WARN("Default mount %s has mount-name set. This is not supported. Behavior may not be consistent.", mount->mountname);
810
    }
811
    if (mount->auth && mount->mountname) {
812
        mount->auth->mount = strdup ((char *)mount->mountname);
813 814 815
    } else if (mount->auth && mount->mounttype == MOUNT_TYPE_DEFAULT ) {
        mount->auth->mount = strdup ("(default mount)");
    }
816 817 818 819 820
    while(current) {
        last = current;
        current = current->next;
    }

821 822
    if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override))
    {
823
        ICECAST_LOG_WARN("Config for mount %s contains fallback options but no fallback mount.", mount->mountname);
824 825
    }

826 827 828 829
    if(last)
        last->next = mount;
    else
        configuration->mounts = mount;
830 831
}

832
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers) {
833 834 835 836
    ice_config_http_header_t *header;
    ice_config_http_header_t *next;
    char *name = NULL;
    char *value = NULL;
837 838 839
    char *tmp;
    int status;
    http_header_type type;
840 841 842 843 844 845 846 847

    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;
        if (xmlStrcmp (node->name, XMLSTR("header")) != 0) break;
        if (!(name = (char *)xmlGetProp(node, XMLSTR("name")))) break;
        if (!(value = (char *)xmlGetProp(node, XMLSTR("value")))) break;

848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
        type = HTTP_HEADER_TYPE_STATIC; /* default */
        if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) {
            if (strcmp(tmp, "static") == 0) {
                type = HTTP_HEADER_TYPE_STATIC;
            } else {
                ICECAST_LOG_WARN("Unknown type %s for HTTP Header %s", tmp, name);
                xmlFree(tmp);
                break;
            }
            xmlFree(tmp);
        }

        status = 0; /* default: any */
        if ((tmp = (char *)xmlGetProp(node, XMLSTR("status")))) {
            status = atoi(tmp);
            xmlFree(tmp);
        }

866 867
        header = calloc(1, sizeof(ice_config_http_header_t));
        if (!header) break;
868
        header->type = type;
869 870
        header->name = name;
        header->value = value;
871
        header->status = status;
872 873 874
        name = NULL;
        value = NULL;

875 876
        if (!*http_headers) {
            *http_headers = header;
877 878
            continue;
        }
879
        next = *http_headers;
880 881 882 883 884 885 886 887 888
        while (next->next) next = next->next;
        next->next = header;
    } while ((node = node->next));
    /* in case we used break we may need to clean those up */
    if (name)
	xmlFree(name);
    if (value)
	xmlFree(value);
}
889

890 891 892 893 894 895 896
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;
897

898 899 900 901 902 903 904 905 906 907 908
    while(current) {
        last = current;
        current = current->next;
    }

    if(last)
        last->next = relay;
    else
        configuration->relay = relay;

    relay->next = NULL;
909
    relay->mp3metadata = 1;
910
    relay->on_demand = configuration->on_demand;
911
    relay->server = (char *)xmlCharStrdup ("127.0.0.1");
912
    relay->mount = (char *)xmlCharStrdup ("/");
913 914 915 916 917

    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

918
        if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
919
            if (relay->server) xmlFree (relay->server);
920 921 922
            relay->server = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
923
        else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
924
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
925 926 927 928 929 930
            if (tmp) {
                relay->port = atoi(tmp);
                xmlFree(tmp);
            } else {
                ICECAST_LOG_WARN("<port> must not be empty.");
            }
931
        }
932
        else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
933
            if (relay->mount) xmlFree (relay->mount);
934 935 936
            relay->mount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
937
        else if (xmlStrcmp (node->name, XMLSTR("local-mount")) == 0) {
938
            if (relay->localmount) xmlFree (relay->localmount);
939 940 941
            relay->localmount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
942
        else if (xmlStrcmp (node->name, XMLSTR("relay-shoutcast-metadata")) == 0) {
943 944 945 946
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            relay->mp3metadata = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
947
        else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
948
            if (relay->username) xmlFree (relay->username);
949 950 951
            relay->username = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
952
        else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
953
            if (relay->password) xmlFree (relay->password);
954 955 956
            relay->password = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
957
        else if (xmlStrcmp (node->name, XMLSTR("on-demand")) == 0) {
958 959 960 961
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            relay->on_demand = atoi(tmp);
            if (tmp) xmlFree(tmp);
        }
962 963 964 965
        else if (xmlStrcmp (node->name, XMLSTR("bind")) == 0) {
            if (relay->bind) xmlFree (relay->bind);
            relay->bind = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
        }
966
    } while ((node = node->next));
Karl Heyes's avatar
Karl Heyes committed
967
    if (relay->localmount == NULL)
968
        relay->localmount = (char *)xmlStrdup (XMLSTR(relay->mount));
969 970 971 972 973 974
}

static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
        ice_config_t *configuration)
{
    char *tmp;
975
    listener_t *listener = calloc (1, sizeof(listener_t));
976

977 978
    if (listener == NULL)
        return;
979 980
    listener->port = 8000;

981 982 983 984
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

985
        if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
986
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
987 988 989 990 991 992 993 994
            if (tmp) {
                if(configuration->port == 0)
                    configuration->port = atoi(tmp);
                listener->port = atoi(tmp);
                xmlFree(tmp);
            } else {
                ICECAST_LOG_WARN("<port> must not be empty.");
            }
995
        }
996
        else if (xmlStrcmp (node->name, XMLSTR("ssl")) == 0) {
997 998 999 1000
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            listener->ssl = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
1001
        else if (xmlStrcmp (node->name, XMLSTR("shoutcast-compat")) == 0) {
1002 1003 1004 1005
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            listener->shoutcast_compat = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
1006 1007 1008 1009 1010
        else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
            if (listener->shoutcast_mount) xmlFree (listener->shoutcast_mount);
            listener->shoutcast_mount = (char *)xmlNodeListGetString(doc, 
                    node->xmlChildrenNode, 1);
        }
1011
        else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
1012
            if (listener->bind_address) xmlFree (listener->bind_address);
1013 1014 1015
            listener->bind_address = (char *)xmlNodeListGetString(doc, 
                    node->xmlChildrenNode, 1);
        }
1016 1017 1018 1019 1020
        else if (xmlStrcmp (node->name, XMLSTR("so-sndbuf")) == 0) {
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            listener->so_sndbuf = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
1021
    } while ((node = node->next));
1022

1023 1024 1025 1026
    /* we know there's at least one of these, so add this new one after the first
     * that way it can be removed easily later on */
    listener->next = configuration->listen_sock->next;
    configuration->listen_sock->next = listener;
1027
    configuration->listen_sock_count++;
1028 1029 1030 1031 1032 1033 1034 1035 1036
    if (listener->shoutcast_mount)
    {
        listener_t *sc_port = calloc (1, sizeof (listener_t));
        sc_port->port = listener->port+1;
        sc_port->shoutcast_compat = 1;
        sc_port->shoutcast_mount = (char*)xmlStrdup (XMLSTR(listener->shoutcast_mount));
        if (listener->bind_address)
            sc_port->bind_address = (char*)xmlStrdup (XMLSTR(listener->bind_address));

1037 1038
        sc_port->next = listener->next;
        listener->next = sc_port;
1039 1040
        configuration->listen_sock_count++;
    }
1041 1042 1043 1044 1045 1046 1047 1048 1049
}

static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
        ice_config_t *configuration)
{
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

1050
        if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
1051
            if (xmlGetProp(node, XMLSTR("mount"))) {
1052
                ICECAST_LOG_ERROR("Mount level source password defined within global <authentication> section.");
1053 1054
            }
            else {
1055
                if (configuration->source_password)
1056 1057 1058 1059
                    xmlFree(configuration->source_password);
                configuration->source_password = 
                    (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            }
1060
        } else if (xmlStrcmp (node->name, XMLSTR("admin-password")) == 0) {
1061 1062 1063 1064
            if(configuration->admin_password)
                xmlFree(configuration->admin_password);
            configuration->admin_password =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1065
        } else if (xmlStrcmp (node->name, XMLSTR("admin-user")) == 0) {
1066 1067 1068 1069
            if(configuration->admin_username)
                xmlFree(configuration->admin_username);
            configuration->admin_username =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1070
        } else if (xmlStrcmp (node->name, XMLSTR("relay-password")) == 0) {
1071 1072 1073 1074
            if(configuration->relay_password)
                xmlFree(configuration->relay_password);
            configuration->relay_password =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1075
        } else if (xmlStrcmp (node->name, XMLSTR("relay-user")) == 0) {
1076 1077 1078 1079
            if(configuration->relay_username)
                xmlFree(configuration->relay_username);
            configuration->relay_username =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
        }
    } 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) {
1090
        ICECAST_LOG_ERROR("Maximum number of yp directories exceeded!");
1091 1092 1093 1094 1095 1096
        return;
    }
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

1097
        if (xmlStrcmp (node->name, XMLSTR("yp-url")) == 0) {
1098 1099 1100 1101
            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);
1102
        } else if (xmlStrcmp (node->name, XMLSTR("yp-url-timeout")) == 0) {
1103 1104 1105
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->yp_url_timeout[configuration->num_yp_directories] = 
                atoi(tmp);
Karl Heyes's avatar
Karl Heyes committed
1106
            if (tmp) xmlFree(tmp);
1107
        } else if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
1108
            _add_server(doc, node->xmlChildrenNode, configuration);
1109
        } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) {
1110
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1111 1112
            configuration->yp_touch_interval[configuration->num_yp_directories] =
                atoi(tmp);
1113 1114 1115
            if (tmp) xmlFree(tmp);
        }
    } while ((node = node->next));
1116 1117
    if (configuration->yp_url [configuration->num_yp_directories] == NULL)
        return;
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
    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;

1131
        if (xmlStrcmp (node->name, XMLSTR("basedir")) == 0) {
1132
            if (configuration->base_dir) xmlFree(configuration->base_dir);
1133
            configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1134
        } else if (xmlStrcmp (node->name, XMLSTR("logdir")) == 0) {
1135 1136 1137 1138
            if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
                ICECAST_LOG_WARN("<logdir> must not be empty.");
                continue;
            }
1139
            if (configuration->log_dir) xmlFree(configuration->log_dir);
1140
            configuration->log_dir = temp;
1141
        } else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) {
1142 1143
            if (configuration->pidfile) xmlFree(configuration->pidfile);
            configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1144 1145 1146 1147 1148 1149
        } else if (xmlStrcmp (node->name, XMLSTR("deny-ip")) == 0) {
            if (configuration->banfile) xmlFree(configuration->banfile);
            configuration->banfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
        } else if (xmlStrcmp (node->name, XMLSTR("allow-ip")) == 0) {
            if (configuration->allowfile) xmlFree(configuration->allowfile);
            configuration->allowfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1150
        } else if (xmlStrcmp (node->name, XMLSTR("ssl-certificate")) == 0) {
1151 1152
            if (configuration->cert_file) xmlFree(configuration->cert_file);
            configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1153 1154 1155
        } else if (xmlStrcmp (node->name, XMLSTR("ssl-allowed-ciphers")) == 0) {
            if (configuration->cipher_list) xmlFree(configuration->cipher_list);
            configuration->cipher_list = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1156
        } else if (xmlStrcmp (node->name, XMLSTR("webroot")) == 0) {
1157 1158 1159 1160
            if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
                ICECAST_LOG_WARN("<webroot> must not be empty.");
                continue;
            }
1161
            if (configuration->webroot_dir) xmlFree(configuration->webroot_dir);
1162
            configuration->webroot_dir = temp;
1163 1164
            if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
                configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
1165
        } else if (xmlStrcmp (node->name, XMLSTR("adminroot")) == 0) {
1166 1167 1168 1169
            if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
                ICECAST_LOG_WARN("<adminroot> must not be empty.");
                continue;
            }
1170
            if (configuration->adminroot_dir) 
1171
                xmlFree(configuration->adminroot_dir);
1172
            configuration->adminroot_dir = (char *)temp;
1173 1174
            if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
                configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
1175
        } else if (xmlStrcmp (node->name, XMLSTR("alias")) == 0) {
1176 1177
            alias = malloc(sizeof(aliases));
            alias->next = NULL;
1178
            alias->source = (char *)xmlGetProp(node, XMLSTR("source"));
1179 1180 1181 1182
            if(alias->source == NULL) {
                free(alias);
                continue;
            }
1183 1184 1185
            alias->destination = (char *)xmlGetProp(node, XMLSTR("destination"));
            if (!alias->destination)
                alias->destination = (char *)xmlGetProp(node, XMLSTR("dest"));
1186 1187 1188 1189 1190 1191
            if(alias->destination == NULL) {
                xmlFree(alias->source);
                free(alias);
                continue;
            }
            temp = NULL;
1192
            temp = (char *)xmlGetProp(node, XMLSTR("port"));
1193 1194 1195 1196 1197 1198
            if(temp != NULL) {
                alias->port = atoi(temp);
                xmlFree(temp);
            }
            else
                alias->port = -1;