cfgfile.c 60.7 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 12
 * Copyright 2011,      Dave 'justdave' Miller <justdave@mozilla.com>.
 * Copyright 2011-2014, Thomas B. "dm8tbr" Ruecker <thomas@ruecker.fi>,
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
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include "thread/thread.h"
#include "cfgfile.h"
#include "refbuf.h"
#include "client.h"
#include "logging.h" 
34
#include "util.h" 
35 36 37 38 39 40

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

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

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

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

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

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

129 130 131 132 133 134 135 136 137 138 139 140
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);
 }
}

141
static inline ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) {
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
    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 */

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

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

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

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    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);
203 204 205 206
    option = mount->auth_options;
    while (option)
    {
        config_options_t *nextopt = option->next;
207 208
        if (option->name)   xmlFree (option->name);
        if (option->value)  xmlFree (option->value);
209 210 211 212
        free (option);
        option = nextopt;
    }
    auth_release (mount->auth);
213
    config_clear_http_header(mount->http_headers);
214 215 216
    free (mount);
}

217 218 219 220 221 222 223
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);
224
        if (listener->shoutcast_mount)  xmlFree (listener->shoutcast_mount);
225 226 227 228
        free (listener);
    }
    return next;
}
229

230 231 232 233 234 235
void config_clear(ice_config_t *c)
{
    ice_config_dir_t *dirnode, *nextdirnode;
    relay_server *relay, *nextrelay;
    mount_proxy *mount, *nextmount;
    aliases *alias, *nextalias;
236
#ifdef USE_YP
237
    int i;
238
#endif
239

240
    free(c->config_filename);
241

Karl Heyes's avatar
Karl Heyes committed
242
    xmlFree (c->server_id);
243 244 245
    if (c->location) xmlFree(c->location);
    if (c->admin) xmlFree(c->admin);
    if (c->source_password) xmlFree(c->source_password);
246 247 248 249
    if (c->admin_username)
        xmlFree(c->admin_username);
    if (c->admin_password)
        xmlFree(c->admin_password);
250 251 252 253
    if (c->relay_username)
        xmlFree(c->relay_username);
    if (c->relay_password)
        xmlFree(c->relay_password);
254 255 256 257 258
    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
259
    if (c->cert_file) xmlFree(c->cert_file);
260
    if (c->cipher_list) xmlFree(c->cipher_list);
Karl Heyes's avatar
Karl Heyes committed
261
    if (c->pidfile)
262
        xmlFree(c->pidfile);
263 264
    if (c->banfile) xmlFree(c->banfile);
    if (c->allowfile) xmlFree(c->allowfile);
265 266 267 268
    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);
269
    if (c->master_server) xmlFree(c->master_server);
270
    if (c->master_username) xmlFree(c->master_username);
271 272 273
    if (c->master_password) xmlFree(c->master_password);
    if (c->user) xmlFree(c->user);
    if (c->group) xmlFree(c->group);
274
    if (c->mimetypes_fn) xmlFree (c->mimetypes_fn);
275

276 277 278
    while ((c->listen_sock = config_clear_listener (c->listen_sock)))
        ;

279 280 281 282 283 284
    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
285
        xmlFree(relay->localmount);
286 287 288 289 290 291 292 293
        free(relay);
        relay = nextrelay;
    }
    thread_mutex_unlock(&(_locks.relay_lock));

    mount = c->mounts;
    while(mount) {
        nextmount = mount->next;
294
        config_clear_mount (mount);
295 296 297 298 299 300 301 302 303
        mount = nextmount;
    }

    alias = c->aliases;
    while(alias) {
        nextalias = alias->next;
        xmlFree(alias->source);
        xmlFree(alias->destination);
        xmlFree(alias->bind_address);
304
        xmlFree(alias->vhost);
305 306 307 308 309 310 311 312 313 314 315
        free(alias);
        alias = nextalias;
    }

    dirnode = c->dir_list;
    while(dirnode) {
        nextdirnode = dirnode->next;
        xmlFree(dirnode->host);
        free(dirnode);
        dirnode = nextdirnode;
    }
316
#ifdef USE_YP
Karl Heyes's avatar
Karl Heyes committed
317
    i = 0;
318
    while (i < c->num_yp_directories)
Karl Heyes's avatar
Karl Heyes committed
319 320 321 322 323
    {
        xmlFree (c->yp_url[i]);
        i++;
    }
#endif
324

325 326
    config_clear_http_header(c->http_headers);

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
    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;
    }

354
    if (xmlStrcmp (node->name, XMLSTR("icecast")) != 0) {
355 356 357 358 359 360
        xmlFreeDoc(doc);
        return CONFIG_EBADROOT;
    }

    config_init_configuration(configuration);

361
    configuration->config_filename = strdup (filename);
362 363 364 365 366

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

    xmlFreeDoc(doc);

367 368
    _merge_mounts_all(configuration);

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

ice_config_t *config_get_config(void)
{
389 390 391 392 393 394 395
    thread_rwlock_rlock(&(_locks.config_lock));
    return &_current_configuration;
}

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

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
static inline void __check_hostname(ice_config_t *configuration) {
    char *p;

    // ensure we have a non-NULL buffer:
    if (!configuration->hostname)
        configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);

    // convert to lower case:
    for (p = configuration->hostname; *p; p++)
        if ( *p >= 'A' && *p <= 'Z' )
            *p += 'a' - 'A';

    configuration->sane_hostname = 0;
    switch (util_hostcheck(configuration->hostname)) {
        case HOSTCHECK_SANE:
            configuration->sane_hostname = 1;
        break;
        case HOSTCHECK_ERROR:
            ICECAST_LOG_ERROR("Can not check hostname \"%s\".", configuration->hostname);
        break;
        case HOSTCHECK_NOT_FQDN:
            ICECAST_LOG_WARN("Warning, <hostname> seems not to be set to a fully qualified fomain name (FQDN). This may cause problems, e.g. with YP directory listings.");
        break;
        case HOSTCHECK_IS_LOCALHOST:
            ICECAST_LOG_WARN("Warning, <hostname> not configured, using default value \"%s\". This will cause problems, e.g. with YP directory listings.", CONFIG_DEFAULT_HOSTNAME);
        break;
        case HOSTCHECK_IS_IPV4:
            ICECAST_LOG_WARN("Warning, <hostname> seems to be set to an IPv4 address. This may cause problems, e.g. with YP directory listings.");
        break;
        case HOSTCHECK_IS_IPV6:
            ICECAST_LOG_WARN("Warning, <hostname> seems to be set to an IPv6 address. This may cause problems, e.g. with YP directory listings.");
        break;
        case HOSTCHECK_BADCHAR:
            ICECAST_LOG_WARN("Warning, <hostname> configured to unusual characters. This may cause problems, e.g. with YP directory listings.");
        break;
    }
}

492 493 494 495 496
static void _parse_root(xmlDocPtr doc, xmlNodePtr node, 
        ice_config_t *configuration)
{
    char *tmp;

497 498 499 500
    configuration->listen_sock = calloc (1, sizeof (*configuration->listen_sock));
    configuration->listen_sock->port = 8000;
    configuration->listen_sock_count = 1;

501 502 503 504
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

505
        if (xmlStrcmp (node->name, XMLSTR("location")) == 0) {
506
            if (configuration->location) xmlFree(configuration->location);
507
            configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
508
        } else if (xmlStrcmp (node->name, XMLSTR("admin")) == 0) {
509
            if (configuration->admin) xmlFree(configuration->admin);
510
            configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
511
        } else if (xmlStrcmp (node->name, XMLSTR("server-id")) == 0) {
512 513
            xmlFree (configuration->server_id);
            configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
514
            ICECAST_LOG_WARN("Warning, server version string override detected. This may lead to unexpected client software behavior.");
515
        } else if(xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
516
            _parse_authentication(doc, node->xmlChildrenNode, configuration);
517
        } else if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
518
            /* TODO: This is the backwards-compatibility location */
519
            ICECAST_LOG_WARN("<source-password> defined outside <authentication>. This is deprecated and will be removed in version 2.5.");
520 521
            if (configuration->source_password) xmlFree(configuration->source_password);
            configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
522
        } else if (xmlStrcmp (node->name, XMLSTR("icelogin")) == 0) {
523 524 525
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->ice_login = atoi(tmp);
            if (tmp) xmlFree(tmp);
526
        } else if (xmlStrcmp (node->name, XMLSTR("fileserve")) == 0) {
527 528 529
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->fileserve = atoi(tmp);
            if (tmp) xmlFree(tmp);
530
        } else if (xmlStrcmp (node->name, XMLSTR("relays-on-demand")) == 0) {
531 532 533
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->on_demand = atoi(tmp);
            if (tmp) xmlFree(tmp);
534
        } else if (xmlStrcmp (node->name, XMLSTR("hostname")) == 0) {
535
            if (configuration->hostname) xmlFree(configuration->hostname);
536
            configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
537
        } else if (xmlStrcmp (node->name, XMLSTR("mime-types")) == 0) {
538 539
            if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn);
            configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
540
        } else if (xmlStrcmp (node->name, XMLSTR("listen-socket")) == 0) {
541
            _parse_listen_socket(doc, node->xmlChildrenNode, configuration);
542
        } else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
543
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
544 545 546 547 548 549 550
            if (tmp) {
                configuration->port = atoi(tmp);
                configuration->listen_sock->port = atoi(tmp);
                xmlFree(tmp);
            } else {
                ICECAST_LOG_WARN("<port> must not be empty.");
            }
551
        } else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
552 553 554
            if (configuration->listen_sock->bind_address) 
                xmlFree(configuration->listen_sock->bind_address);
            configuration->listen_sock->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
555
        } else if (xmlStrcmp (node->name, XMLSTR("master-server")) == 0) {
556 557
            if (configuration->master_server) xmlFree(configuration->master_server);
            configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
558
        } else if (xmlStrcmp (node->name, XMLSTR("master-username")) == 0) {
559 560
            if (configuration->master_username) xmlFree(configuration->master_username);
            configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
561
        } else if (xmlStrcmp (node->name, XMLSTR("master-password")) == 0) {
562 563
            if (configuration->master_password) xmlFree(configuration->master_password);
            configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
564
        } else if (xmlStrcmp (node->name, XMLSTR("master-server-port")) == 0) {
565 566
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->master_server_port = atoi(tmp);
567
            xmlFree (tmp);
568
        } else if (xmlStrcmp (node->name, XMLSTR("master-update-interval")) == 0) {
569 570
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->master_update_interval = atoi(tmp);
571
            xmlFree (tmp);
572
        } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
573
            if (configuration->shoutcast_mount) xmlFree(configuration->shoutcast_mount);
574
            configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
575
        } else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
576
            _parse_limits(doc, node->xmlChildrenNode, configuration);
577
        } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
578
            _parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers));
579
        } else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
580
            _parse_relay(doc, node->xmlChildrenNode, configuration);
581
        } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
582
            _parse_mount(doc, node, configuration);
583
        } else if (xmlStrcmp (node->name, XMLSTR("directory")) == 0) {
584
            _parse_directory(doc, node->xmlChildrenNode, configuration);
585
        } else if (xmlStrcmp (node->name, XMLSTR("paths")) == 0) {
586
            _parse_paths(doc, node->xmlChildrenNode, configuration);
587
        } else if (xmlStrcmp (node->name, XMLSTR("logging")) == 0) {
588
            _parse_logging(doc, node->xmlChildrenNode, configuration);
589
        } else if (xmlStrcmp (node->name, XMLSTR("security")) == 0) {
590 591 592
            _parse_security(doc, node->xmlChildrenNode, configuration);
        }
    } while ((node = node->next));
593 594 595 596 597 598 599 600

    /* 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--;
    }
601 602
    if (configuration->port == 0)
        configuration->port = 8000;
603 604 605 606 607

   /* 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).");

608
  __check_hostname(configuration);
609 610 611 612 613 614 615 616 617 618 619 620

  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);
  }
621 622 623 624 625 626 627 628 629 630 631
}

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

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

632
        if (xmlStrcmp (node->name, XMLSTR("clients")) == 0) {
633 634 635
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->client_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
636
        } else if (xmlStrcmp (node->name, XMLSTR("sources")) == 0) {
637 638 639
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->source_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
640
        } else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
641 642 643
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->queue_size_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
644
        } else if (xmlStrcmp (node->name, XMLSTR("threadpool")) == 0) {
645
            ICECAST_LOG_WARN("<threadpool> deprecated and will be removed in version 2.5.");
646
        } else if (xmlStrcmp (node->name, XMLSTR("client-timeout")) == 0) {
647 648 649
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->client_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
650
        } else if (xmlStrcmp (node->name, XMLSTR("header-timeout")) == 0) {
651 652 653
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->header_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
654
        } else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
655 656 657
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->source_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
658
        } else if (xmlStrcmp (node->name, XMLSTR("burst-on-connect")) == 0) {
659
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Karl Heyes's avatar
Karl Heyes committed
660 661 662
            if (atoi(tmp) == 0)
                configuration->burst_size = 0;
            if (tmp) xmlFree(tmp);
663
        } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
Karl Heyes's avatar
Karl Heyes committed
664 665
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->burst_size = atoi(tmp);
666
            if (tmp) xmlFree(tmp);
667 668 669 670 671 672 673 674 675 676 677 678
        }
    } 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;
    
Karl Heyes's avatar
Karl Heyes committed
679
    /* default <mount> settings */
680
    mount->mounttype = MOUNT_TYPE_NORMAL;
681
    mount->max_listeners = -1;
Karl Heyes's avatar
Karl Heyes committed
682
    mount->burst_size = -1;
683
    mount->mp3_meta_interval = -1;
684
    mount->yp_public = -1;
685 686
    mount->next = NULL;

687 688 689 690 691 692 693 694 695
    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 {
696
	    ICECAST_LOG_WARN("Unknown mountpoint type: %s", tmp);
697 698 699
            config_clear_mount (mount);
            return;
	}
700
	xmlFree(tmp);
701 702 703 704
    }

    node = node->xmlChildrenNode;

705 706 707 708
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

709 710
        if (xmlStrcmp (node->name, XMLSTR("mount-name")) == 0) {
            mount->mountname = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
711
        }
712
        else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
713 714 715
            mount->username = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
716
        else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
717 718 719
            mount->password = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
720
        else if (xmlStrcmp (node->name, XMLSTR("dump-file")) == 0) {
721 722
            mount->dumpfile = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
Karl Heyes's avatar
Karl Heyes committed
723
        }
724
        else if (xmlStrcmp (node->name, XMLSTR("intro")) == 0) {
Karl Heyes's avatar
Karl Heyes committed
725 726
            mount->intro_filename = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
727
        }
728
        else if (xmlStrcmp (node->name, XMLSTR("fallback-mount")) == 0) {
729 730 731
            mount->fallback_mount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
732
        else if (xmlStrcmp (node->name, XMLSTR("fallback-when-full")) == 0) {
733 734 735 736
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->fallback_when_full = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
737
        else if (xmlStrcmp (node->name, XMLSTR("max-listeners")) == 0) {
738 739 740 741
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->max_listeners = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
742
        else if (xmlStrcmp (node->name, XMLSTR("charset")) == 0) {
743 744 745
            mount->charset = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
746
        else if (xmlStrcmp (node->name, XMLSTR("mp3-metadata-interval")) == 0) {
747 748 749 750
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->mp3_meta_interval = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
751
        else if (xmlStrcmp (node->name, XMLSTR("fallback-override")) == 0) {
Michael Smith's avatar
Michael Smith committed
752 753 754 755
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->fallback_override = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
756
        else if (xmlStrcmp (node->name, XMLSTR("no-mount")) == 0) {
Michael Smith's avatar
Michael Smith committed
757 758 759 760
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->no_mount = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
761
        else if (xmlStrcmp (node->name, XMLSTR("no-yp")) == 0) {
762
            ICECAST_LOG_WARN("<no-yp> defined. Please use <public>. This is deprecated and will be removed in version 2.5.");
Karl Heyes's avatar
Karl Heyes committed
763
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
764
            mount->yp_public = atoi(tmp) == 0 ? -1 : 0;
Karl Heyes's avatar
Karl Heyes committed
765 766
            if(tmp) xmlFree(tmp);
        }
767
        else if (xmlStrcmp (node->name, XMLSTR("hidden")) == 0) {
768 769 770 771
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->hidden = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
772
        else if (xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
773
            mount->auth = auth_get_authenticator (node);
Michael Smith's avatar
Michael Smith committed
774
        }
775
        else if (xmlStrcmp (node->name, XMLSTR("on-connect")) == 0) {
776 777 778
            mount->on_connect = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
779
        else if (xmlStrcmp (node->name, XMLSTR("on-disconnect")) == 0) {
780 781 782
            mount->on_disconnect = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
783
        else if (xmlStrcmp (node->name, XMLSTR("max-listener-duration")) == 0) {
784 785 786 787
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->max_listener_duration = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
788
        else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
789 790 791 792
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->queue_size_limit = atoi (tmp);
            if(tmp) xmlFree(tmp);
        }
793
        else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
794 795 796 797 798 799
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            if (tmp)
            {
                mount->source_timeout = atoi (tmp);
                xmlFree(tmp);
            }
800
        } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
Karl Heyes's avatar
Karl Heyes committed
801 802 803
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->burst_size = atoi(tmp);
            if (tmp) xmlFree(tmp);
804
        } else if (xmlStrcmp (node->name, XMLSTR("cluster-password")) == 0) {
805 806
            mount->cluster_password = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
807
        } else if (xmlStrcmp (node->name, XMLSTR("stream-name")) == 0) {
808 809
            mount->stream_name = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
810
        } else if (xmlStrcmp (node->name, XMLSTR("stream-description")) == 0) {
811 812
            mount->stream_description = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
813
        } else if (xmlStrcmp (node->name, XMLSTR("stream-url")) == 0) {
814 815
            mount->stream_url = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
816
        } else if (xmlStrcmp (node->name, XMLSTR("genre")) == 0) {
817 818
            mount->stream_genre = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
819
        } else if (xmlStrcmp (node->name, XMLSTR("bitrate")) == 0) {
820 821
            mount->bitrate = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
822
        } else if (xmlStrcmp (node->name, XMLSTR("public")) == 0) {
823 824 825
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->yp_public = atoi (tmp);
            if(tmp) xmlFree(tmp);
826
        } else if (xmlStrcmp (node->name, XMLSTR("type")) == 0) {
827 828
            mount->type = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
829
        } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
830 831
            mount->subtype = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
832 833
        } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
            _parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers));
834
        }
835
    } while ((node = node->next));
836 837

    /* make sure we have at least the mountpoint name */
838
    if (mount->mountname == NULL && mount->mounttype != MOUNT_TYPE_DEFAULT)
839 840 841 842
    {
        config_clear_mount (mount);
        return;
    }
843 844
    else if (mount->mountname != NULL && mount->mounttype == MOUNT_TYPE_DEFAULT)
    {
845
    	ICECAST_LOG_WARN("Default mount %s has mount-name set. This is not supported. Behavior may not be consistent.", mount->mountname);
846
    }
847
    if (mount->auth && mount->mountname) {
848
        mount->auth->mount = strdup ((char *)mount->mountname);
849 850 851
    } else if (mount->auth && mount->mounttype == MOUNT_TYPE_DEFAULT ) {
        mount->auth->mount = strdup ("(default mount)");
    }
852 853 854 855 856
    while(current) {
        last = current;
        current = current->next;
    }

857 858
    if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override))
    {
859
        ICECAST_LOG_WARN("Config for mount %s contains fallback options but no fallback mount.", mount->mountname);
860 861
    }

862 863 864 865
    if(last)
        last->next = mount;
    else
        configuration->mounts = mount;
866 867
}

868
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers) {
869 870 871 872
    ice_config_http_header_t *header;
    ice_config_http_header_t *next;
    char *name = NULL;
    char *value = NULL;
873 874 875
    char *tmp;
    int status;
    http_header_type type;
876 877 878 879 880 881 882 883

    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;

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
        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);
        }

902 903
        header = calloc(1, sizeof(ice_config_http_header_t));
        if (!header) break;
904
        header->type = type;
905 906
        header->name = name;
        header->value = value;
907
        header->status = status;
908 909 910
        name = NULL;
        value = NULL;

911 912
        if (!*http_headers) {
            *http_headers = header;
913 914
            continue;
        }
915
        next = *http_headers;
916 917 918 919 920 921 922 923 924
        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);
}
925

926 927 928 929 930 931 932
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;
933

934 935 936 937 938 939 940 941 942 943 944
    while(current) {
        last = current;
        current = current->next;
    }

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

    relay->next = NULL;
945
    relay->mp3metadata = 1;
946
    relay->on_demand = configuration->on_demand;
947
    relay->server = (char *)xmlCharStrdup ("127.0.0.1");
948
    relay->mount = (char *)xmlCharStrdup ("/");
949 950 951 952 953

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

954
        if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
955
            if (relay->server) xmlFree (relay->server);
956 957 958
            relay->server = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
959
        else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
960
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
961 962 963 964 965 966
            if (tmp) {
                relay->port = atoi(tmp);
                xmlFree(tmp);
            } else {
                ICECAST_LOG_WARN("<port> must not be empty.");
            }
967
        }
968
        else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
969
            if (relay->mount) xmlFree (relay->mount);
970 971 972
            relay->mount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
973
        else if (xmlStrcmp (node->name, XMLSTR("local-mount")) == 0) {
974
            if (relay->localmount) xmlFree (relay->localmount);
975 976 977
            relay->localmount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
978
        else if (xmlStrcmp (node->name, XMLSTR("relay-shoutcast-metadata")) == 0) {
979 980 981 982
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            relay->mp3metadata = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
983
        else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
984
            if (relay->username) xmlFree (relay->username);
985 986 987
            relay->username = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
988
        else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
989
            if (relay->password) xmlFree (relay->password);
990 991 992
            relay->password = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
993
        else if (xmlStrcmp (node->name, XMLSTR("on-demand")) == 0) {
994 995 996 997
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            relay->on_demand = atoi(tmp);
            if (tmp) xmlFree(tmp);
        }
998 999 1000 1001
        else if (xmlStrcmp (node->name, XMLSTR("bind")) == 0) {
            if (relay->bind) xmlFree (relay->bind);
            relay->bind = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
        }
1002
    } while ((node = node->next));
Karl Heyes's avatar
Karl Heyes committed
1003
    if (relay->localmount == NULL)
1004
        relay->localmount = (char *)xmlStrdup (XMLSTR(relay->mount));
1005 1006 1007 1008 1009 1010
}

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

1013 1014
    if (listener == NULL)
        return;
1015 1016
    listener->port = 8000;

1017 1018 1019 1020
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

1021
        if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
1022
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1023 1024 1025 1026 1027 1028 1029 1030
            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.");
            }
1031
        }
1032
        else if (xmlStrcmp (node->name, XMLSTR("ssl")) == 0) {
1033 1034 1035 1036
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            listener->ssl = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
1037
        else if (xmlStrcmp (node->name, XMLSTR("shoutcast-compat")) == 0) {
1038 1039 1040 1041
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            listener->shoutcast_compat = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
1042 1043 1044 1045 1046
        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);
        }
1047
        else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
1048
            if (listener->bind_address) xmlFree (listener->bind_address);
1049 1050 1051
            listener->bind_address = (char *)xmlNodeListGetString(doc, 
                    node->xmlChildrenNode, 1);
        }
1052 1053 1054 1055 1056
        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);
        }
1057
    } while ((node = node->next));
1058

1059 1060 1061 1062
    /* 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;
1063
    configuration->listen_sock_count++;
1064 1065 1066 1067 1068 1069 1070 1071 1072
    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));

1073 1074
        sc_port->next = listener->next;
        listener->next = sc_port;
1075 1076
        configuration->listen_sock_count++;
    }
1077 1078 1079 1080 1081 1082 1083 1084 1085
}

static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
        ice_config_t *configuration