cfgfile.c 44.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/* 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).
 */

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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
34
#define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (500*1024)
35
#define CONFIG_DEFAULT_BURST_SIZE (64*1024)
36 37 38 39 40 41
#define CONFIG_DEFAULT_THREADPOOL_SIZE 4
#define CONFIG_DEFAULT_CLIENT_TIMEOUT 30
#define CONFIG_DEFAULT_HEADER_TIMEOUT 15
#define CONFIG_DEFAULT_SOURCE_TIMEOUT 10
#define CONFIG_DEFAULT_SOURCE_PASSWORD "changeme"
#define CONFIG_DEFAULT_RELAY_PASSWORD "changeme"
42
#define CONFIG_DEFAULT_MASTER_USERNAME "relay"
43
#define CONFIG_DEFAULT_SHOUTCAST_MOUNT "/stream"
44 45 46 47
#define CONFIG_DEFAULT_ICE_LOGIN 0
#define CONFIG_DEFAULT_FILESERVE 1
#define CONFIG_DEFAULT_TOUCH_FREQ 5
#define CONFIG_DEFAULT_HOSTNAME "localhost"
48
#define CONFIG_DEFAULT_PLAYLIST_LOG NULL
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#define CONFIG_DEFAULT_ACCESS_LOG "access.log"
#define CONFIG_DEFAULT_ERROR_LOG "error.log"
#define CONFIG_DEFAULT_LOG_LEVEL 4
#define CONFIG_DEFAULT_CHROOT 0
#define CONFIG_DEFAULT_CHUID 0
#define CONFIG_DEFAULT_USER NULL
#define CONFIG_DEFAULT_GROUP NULL
#define CONFIG_MASTER_UPDATE_INTERVAL 120
#define CONFIG_YP_URL_TIMEOUT 10

#ifndef _WIN32
#define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast"
#define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs"
#define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot"
#define CONFIG_DEFAULT_ADMINROOT_DIR "/usr/local/icecast/admin"
64
#define MIMETYPESFILE "/etc/mime.types"
65 66 67 68 69
#else
#define CONFIG_DEFAULT_BASE_DIR ".\\"
#define CONFIG_DEFAULT_LOG_DIR ".\\logs"
#define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot"
#define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin"
70
#define MIMETYPESFILE ".\\mime.types"
71 72 73 74 75 76 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);
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);

91
static void create_locks(void) {
92
    thread_mutex_create(&_locks.relay_lock);
93
    thread_rwlock_create(&_locks.config_lock);
94 95
}

96
static void release_locks(void) {
97
    thread_mutex_destroy(&_locks.relay_lock);
98
    thread_rwlock_destroy(&_locks.config_lock);
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
}

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

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
static void config_clear_mount (mount_proxy *mount)
{
    config_options_t *option;

    xmlFree (mount->mountname);
    xmlFree (mount->username);
    xmlFree (mount->password);
    xmlFree (mount->dumpfile);
    xmlFree (mount->intro_filename);
    xmlFree (mount->on_connect);
    xmlFree (mount->on_disconnect);
    xmlFree (mount->fallback_mount);
    xmlFree (mount->stream_name);
    xmlFree (mount->stream_description);
    xmlFree (mount->stream_url);
    xmlFree (mount->stream_genre);
    xmlFree (mount->bitrate);
    xmlFree (mount->type);
136
    xmlFree (mount->charset);
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    xmlFree (mount->cluster_password);

    xmlFree (mount->auth_type);
    option = mount->auth_options;
    while (option)
    {
        config_options_t *nextopt = option->next;
        xmlFree (option->name);
        xmlFree (option->value);
        free (option);
        option = nextopt;
    }
    auth_release (mount->auth);
    free (mount);
}

153 154 155 156 157 158 159 160 161 162 163
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);
        free (listener);
    }
    return next;
}
164

165 166 167 168 169 170 171 172
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;

173
    free(c->config_filename);
174

Karl Heyes's avatar
Karl Heyes committed
175
    xmlFree (c->server_id);
176 177 178
    if (c->location) xmlFree(c->location);
    if (c->admin) xmlFree(c->admin);
    if (c->source_password) xmlFree(c->source_password);
179 180 181 182
    if (c->admin_username)
        xmlFree(c->admin_username);
    if (c->admin_password)
        xmlFree(c->admin_password);
183 184 185 186
    if (c->relay_username)
        xmlFree(c->relay_username);
    if (c->relay_password)
        xmlFree(c->relay_password);
187 188 189 190 191
    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
192
    if (c->cert_file) xmlFree(c->cert_file);
Karl Heyes's avatar
Karl Heyes committed
193
    if (c->pidfile)
194
        xmlFree(c->pidfile);
195 196
    if (c->banfile) xmlFree(c->banfile);
    if (c->allowfile) xmlFree(c->allowfile);
197 198 199 200
    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);
201
    if (c->master_server) xmlFree(c->master_server);
202
    if (c->master_username) xmlFree(c->master_username);
203 204 205
    if (c->master_password) xmlFree(c->master_password);
    if (c->user) xmlFree(c->user);
    if (c->group) xmlFree(c->group);
206
    if (c->mimetypes_fn) xmlFree (c->mimetypes_fn);
207

208 209 210
    while ((c->listen_sock = config_clear_listener (c->listen_sock)))
        ;

211 212 213 214 215 216
    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
217
        xmlFree(relay->localmount);
218 219 220 221 222 223 224 225
        free(relay);
        relay = nextrelay;
    }
    thread_mutex_unlock(&(_locks.relay_lock));

    mount = c->mounts;
    while(mount) {
        nextmount = mount->next;
226
        config_clear_mount (mount);
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
        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;
    }
247
#ifdef USE_YP
Karl Heyes's avatar
Karl Heyes committed
248
    i = 0;
249
    while (i < c->num_yp_directories)
Karl Heyes's avatar
Karl Heyes committed
250 251 252 253 254
    {
        xmlFree (c->yp_url[i]);
        i++;
    }
#endif
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284

    memset(c, 0, sizeof(ice_config_t));
}

int config_initial_parse_file(const char *filename)
{
    /* Since we're already pointing at it, we don't need to copy it in place */
    return config_parse_file(filename, &_current_configuration);
}

int config_parse_file(const char *filename, ice_config_t *configuration)
{
    xmlDocPtr doc;
    xmlNodePtr node;

    if (filename == NULL || strcmp(filename, "") == 0) return CONFIG_EINSANE;
    
    xmlInitParser();
    doc = xmlParseFile(filename);
    if (doc == NULL) {
        return CONFIG_EPARSE;
    }

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

285
    if (xmlStrcmp (node->name, XMLSTR("icecast")) != 0) {
286 287 288 289 290 291 292
        xmlFreeDoc(doc);
        xmlCleanupParser();
        return CONFIG_EBADROOT;
    }

    config_init_configuration(configuration);

293
    configuration->config_filename = strdup (filename);
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

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

    xmlFreeDoc(doc);

    return 0;
}

int config_parse_cmdline(int arg, char **argv)
{
    return 0;
}

ice_config_locks *config_locks(void)
{
    return &_locks;
}

void config_release_config(void)
{
314
    thread_rwlock_unlock(&(_locks.config_lock));
315 316 317 318
}

ice_config_t *config_get_config(void)
{
319 320 321 322 323 324 325
    thread_rwlock_rlock(&(_locks.config_lock));
    return &_current_configuration;
}

ice_config_t *config_grab_config(void)
{
    thread_rwlock_wlock(&(_locks.config_lock));
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    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)
{
341
    configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
342
    configuration->server_id = (char *)xmlCharStrdup (ICECAST_VERSION_STRING);
343
    configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN);
344 345 346 347 348 349 350
    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;
351 352
    configuration->source_password = (char *)xmlCharStrdup (CONFIG_DEFAULT_SOURCE_PASSWORD);
    configuration->shoutcast_mount = (char *)xmlCharStrdup (CONFIG_DEFAULT_SHOUTCAST_MOUNT);
353 354 355
    configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
    configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
    configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
356
    configuration->on_demand = 0;
357
    configuration->dir_list = NULL;
358 359
    configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
    configuration->mimetypes_fn = (char *)xmlCharStrdup (MIMETYPESFILE);
360
    configuration->port = 8000;
361 362 363
    configuration->master_server = NULL;
    configuration->master_server_port = 0;
    configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
364
    configuration->master_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
365
    configuration->master_password = NULL;
366 367 368 369 370 371 372
    configuration->base_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_BASE_DIR);
    configuration->log_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOG_DIR);
    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);
373 374 375
    configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
    configuration->chroot = CONFIG_DEFAULT_CHROOT;
    configuration->chuid = CONFIG_DEFAULT_CHUID;
376 377
    configuration->user = NULL;
    configuration->group = NULL;
378
    configuration->num_yp_directories = 0;
379
    configuration->relay_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
380
    configuration->relay_password = NULL;
Karl Heyes's avatar
Karl Heyes committed
381
    /* default to a typical prebuffer size used by clients */
382
    configuration->burst_size = CONFIG_DEFAULT_BURST_SIZE;
383 384 385 386 387 388 389
}

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

390 391 392 393
    configuration->listen_sock = calloc (1, sizeof (*configuration->listen_sock));
    configuration->listen_sock->port = 8000;
    configuration->listen_sock_count = 1;

394 395 396 397
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

398
        if (xmlStrcmp (node->name, XMLSTR("location")) == 0) {
399
            if (configuration->location) xmlFree(configuration->location);
400
            configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
401
        } else if (xmlStrcmp (node->name, XMLSTR("admin")) == 0) {
402
            if (configuration->admin) xmlFree(configuration->admin);
403
            configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
404
        } else if (xmlStrcmp (node->name, XMLSTR("server-id")) == 0) {
405 406
            xmlFree (configuration->server_id);
            configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
407
        } else if(xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
408
            _parse_authentication(doc, node->xmlChildrenNode, configuration);
409
        } else if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
410 411
            /* TODO: This is the backwards-compatibility location */
            char *mount, *pass;
412
            if ((mount = (char *)xmlGetProp(node, XMLSTR("mount"))) != NULL) {
413 414 415 416
                pass = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
                /* FIXME: This is a placeholder for per-mount passwords */
            }
            else {
417
                if (configuration->source_password) xmlFree(configuration->source_password);
418 419
                configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            }
420
        } else if (xmlStrcmp (node->name, XMLSTR("icelogin")) == 0) {
421 422 423
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->ice_login = atoi(tmp);
            if (tmp) xmlFree(tmp);
424
        } else if (xmlStrcmp (node->name, XMLSTR("fileserve")) == 0) {
425 426 427
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->fileserve = atoi(tmp);
            if (tmp) xmlFree(tmp);
428
        } else if (xmlStrcmp (node->name, XMLSTR("relays-on-demand")) == 0) {
429 430 431
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->on_demand = atoi(tmp);
            if (tmp) xmlFree(tmp);
432
        } else if (xmlStrcmp (node->name, XMLSTR("hostname")) == 0) {
433
            if (configuration->hostname) xmlFree(configuration->hostname);
434
            configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
435
        } else if (xmlStrcmp (node->name, XMLSTR("mime-types")) == 0) {
436 437
            if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn);
            configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
438
        } else if (xmlStrcmp (node->name, XMLSTR("listen-socket")) == 0) {
439
            _parse_listen_socket(doc, node->xmlChildrenNode, configuration);
440
        } else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
441 442
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->port = atoi(tmp);
443
            configuration->listen_sock->port = atoi(tmp);
444
            if (tmp) xmlFree(tmp);
445
        } else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
446 447 448
            if (configuration->listen_sock->bind_address) 
                xmlFree(configuration->listen_sock->bind_address);
            configuration->listen_sock->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
449
        } else if (xmlStrcmp (node->name, XMLSTR("master-server")) == 0) {
450 451
            if (configuration->master_server) xmlFree(configuration->master_server);
            configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
452
        } else if (xmlStrcmp (node->name, XMLSTR("master-username")) == 0) {
453 454
            if (configuration->master_username) xmlFree(configuration->master_username);
            configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
455
        } else if (xmlStrcmp (node->name, XMLSTR("master-password")) == 0) {
456 457
            if (configuration->master_password) xmlFree(configuration->master_password);
            configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
458
        } else if (xmlStrcmp (node->name, XMLSTR("master-server-port")) == 0) {
459 460
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->master_server_port = atoi(tmp);
461
            xmlFree (tmp);
462
        } else if (xmlStrcmp (node->name, XMLSTR("master-update-interval")) == 0) {
463 464
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->master_update_interval = atoi(tmp);
465
            xmlFree (tmp);
466
        } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
467
            if (configuration->shoutcast_mount) xmlFree(configuration->shoutcast_mount);
468
            configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
469
        } else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
470
            _parse_limits(doc, node->xmlChildrenNode, configuration);
471
        } else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
472
            _parse_relay(doc, node->xmlChildrenNode, configuration);
473
        } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
474
            _parse_mount(doc, node->xmlChildrenNode, configuration);
475
        } else if (xmlStrcmp (node->name, XMLSTR("directory")) == 0) {
476
            _parse_directory(doc, node->xmlChildrenNode, configuration);
477
        } else if (xmlStrcmp (node->name, XMLSTR("paths")) == 0) {
478
            _parse_paths(doc, node->xmlChildrenNode, configuration);
479
        } else if (xmlStrcmp (node->name, XMLSTR("logging")) == 0) {
480
            _parse_logging(doc, node->xmlChildrenNode, configuration);
481
        } else if (xmlStrcmp (node->name, XMLSTR("security")) == 0) {
482 483 484 485 486 487 488 489 490 491 492 493 494 495
            _parse_security(doc, node->xmlChildrenNode, configuration);
        }
    } while ((node = node->next));
}

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

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

496
        if (xmlStrcmp (node->name, XMLSTR("clients")) == 0) {
497 498 499
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->client_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
500
        } else if (xmlStrcmp (node->name, XMLSTR("sources")) == 0) {
501 502 503
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->source_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
504
        } else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
505 506 507
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->queue_size_limit = atoi(tmp);
            if (tmp) xmlFree(tmp);
508
        } else if (xmlStrcmp (node->name, XMLSTR("threadpool")) == 0) {
509 510 511
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->threadpool_size = atoi(tmp);
            if (tmp) xmlFree(tmp);
512
        } else if (xmlStrcmp (node->name, XMLSTR("client-timeout")) == 0) {
513 514 515
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->client_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
516
        } else if (xmlStrcmp (node->name, XMLSTR("header-timeout")) == 0) {
517 518 519
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->header_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
520
        } else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
521 522 523
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->source_timeout = atoi(tmp);
            if (tmp) xmlFree(tmp);
524
        } else if (xmlStrcmp (node->name, XMLSTR("burst-on-connect")) == 0) {
525
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Karl Heyes's avatar
Karl Heyes committed
526 527 528
            if (atoi(tmp) == 0)
                configuration->burst_size = 0;
            if (tmp) xmlFree(tmp);
529
        } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
Karl Heyes's avatar
Karl Heyes committed
530 531
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->burst_size = atoi(tmp);
532
            if (tmp) xmlFree(tmp);
533 534 535 536 537 538 539 540 541 542 543 544
        }
    } 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
545
    /* default <mount> settings */
546
    mount->max_listeners = -1;
Karl Heyes's avatar
Karl Heyes committed
547
    mount->burst_size = -1;
548
    mount->mp3_meta_interval = -1;
549
    mount->yp_public = -1;
550 551 552 553 554 555
    mount->next = NULL;

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

556 557
        if (xmlStrcmp (node->name, XMLSTR("mount-name")) == 0) {
            mount->mountname = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
558
        }
559
        else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
560 561 562
            mount->username = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
563
        else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
564 565 566
            mount->password = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
567
        else if (xmlStrcmp (node->name, XMLSTR("dump-file")) == 0) {
568 569
            mount->dumpfile = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
Karl Heyes's avatar
Karl Heyes committed
570
        }
571
        else if (xmlStrcmp (node->name, XMLSTR("intro")) == 0) {
Karl Heyes's avatar
Karl Heyes committed
572 573
            mount->intro_filename = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
574
        }
575
        else if (xmlStrcmp (node->name, XMLSTR("fallback-mount")) == 0) {
576 577 578
            mount->fallback_mount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
579
        else if (xmlStrcmp (node->name, XMLSTR("fallback-when-full")) == 0) {
580 581 582 583
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->fallback_when_full = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
584
        else if (xmlStrcmp (node->name, XMLSTR("max-listeners")) == 0) {
585 586 587 588
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->max_listeners = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
589
        else if (xmlStrcmp (node->name, XMLSTR("charset")) == 0) {
590 591 592
            mount->charset = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
593
        else if (xmlStrcmp (node->name, XMLSTR("mp3-metadata-interval")) == 0) {
594 595 596 597
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->mp3_meta_interval = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
598
        else if (xmlStrcmp (node->name, XMLSTR("fallback-override")) == 0) {
Michael Smith's avatar
Michael Smith committed
599 600 601 602
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->fallback_override = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
603
        else if (xmlStrcmp (node->name, XMLSTR("no-mount")) == 0) {
Michael Smith's avatar
Michael Smith committed
604 605 606 607
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->no_mount = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
608
        else if (xmlStrcmp (node->name, XMLSTR("no-yp")) == 0) {
Karl Heyes's avatar
Karl Heyes committed
609
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
610
            mount->yp_public = atoi(tmp) == 0 ? -1 : 0;
Karl Heyes's avatar
Karl Heyes committed
611 612
            if(tmp) xmlFree(tmp);
        }
613
        else if (xmlStrcmp (node->name, XMLSTR("hidden")) == 0) {
614 615 616 617
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->hidden = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
618
        else if (xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
619
            mount->auth = auth_get_authenticator (node);
Michael Smith's avatar
Michael Smith committed
620
        }
621
        else if (xmlStrcmp (node->name, XMLSTR("on-connect")) == 0) {
622 623 624
            mount->on_connect = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
625
        else if (xmlStrcmp (node->name, XMLSTR("on-disconnect")) == 0) {
626 627 628
            mount->on_disconnect = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
629
        else if (xmlStrcmp (node->name, XMLSTR("max-listener-duration")) == 0) {
630 631 632 633
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->max_listener_duration = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
634
        else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
635 636 637 638
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->queue_size_limit = atoi (tmp);
            if(tmp) xmlFree(tmp);
        }
639
        else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
640 641 642 643 644 645
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            if (tmp)
            {
                mount->source_timeout = atoi (tmp);
                xmlFree(tmp);
            }
646
        } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
Karl Heyes's avatar
Karl Heyes committed
647 648 649
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->burst_size = atoi(tmp);
            if (tmp) xmlFree(tmp);
650
        } else if (xmlStrcmp (node->name, XMLSTR("cluster-password")) == 0) {
651 652
            mount->cluster_password = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
653
        } else if (xmlStrcmp (node->name, XMLSTR("stream-name")) == 0) {
654 655
            mount->stream_name = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
656
        } else if (xmlStrcmp (node->name, XMLSTR("stream-description")) == 0) {
657 658
            mount->stream_description = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
659
        } else if (xmlStrcmp (node->name, XMLSTR("stream-url")) == 0) {
660 661
            mount->stream_url = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
662
        } else if (xmlStrcmp (node->name, XMLSTR("genre")) == 0) {
663 664
            mount->stream_genre = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
665
        } else if (xmlStrcmp (node->name, XMLSTR("bitrate")) == 0) {
666 667
            mount->bitrate = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
668
        } else if (xmlStrcmp (node->name, XMLSTR("public")) == 0) {
669 670 671
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            mount->yp_public = atoi (tmp);
            if(tmp) xmlFree(tmp);
672
        } else if (xmlStrcmp (node->name, XMLSTR("type")) == 0) {
673 674
            mount->type = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
675
        } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
676 677
            mount->subtype = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
678
        }
679
    } while ((node = node->next));
680 681 682 683 684 685 686

    /* make sure we have at least the mountpoint name */
    if (mount->mountname == NULL)
    {
        config_clear_mount (mount);
        return;
    }
687
    if (mount->auth)
688
        mount->auth->mount = strdup ((char *)mount->mountname);
689 690 691 692 693 694 695 696 697
    while(current) {
        last = current;
        current = current->next;
    }

    if(last)
        last->next = mount;
    else
        configuration->mounts = mount;
698 699
}

700

701 702 703 704 705 706 707
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;
708

709 710 711 712 713 714 715 716 717 718 719
    while(current) {
        last = current;
        current = current->next;
    }

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

    relay->next = NULL;
720
    relay->mp3metadata = 1;
721
    relay->on_demand = configuration->on_demand;
722 723 724 725 726

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

727
        if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
728
            if (relay->server) xmlFree (relay->server);
729 730 731
            relay->server = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
732
        else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
733 734 735 736
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            relay->port = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
737
        else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
738
            if (relay->mount) xmlFree (relay->mount);
739 740 741
            relay->mount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
742
        else if (xmlStrcmp (node->name, XMLSTR("local-mount")) == 0) {
743
            if (relay->localmount) xmlFree (relay->localmount);
744 745 746
            relay->localmount = (char *)xmlNodeListGetString(
                    doc, node->xmlChildrenNode, 1);
        }
747
        else if (xmlStrcmp (node->name, XMLSTR("relay-shoutcast-metadata")) == 0) {
748 749 750 751
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            relay->mp3metadata = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
752
        else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
753
            if (relay->username) xmlFree (relay->username);
754 755 756
            relay->username = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
757
        else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
758
            if (relay->password) xmlFree (relay->password);
759 760 761
            relay->password = (char *)xmlNodeListGetString(doc,
                    node->xmlChildrenNode, 1);
        }
762
        else if (xmlStrcmp (node->name, XMLSTR("on-demand")) == 0) {
763 764 765 766
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            relay->on_demand = atoi(tmp);
            if (tmp) xmlFree(tmp);
        }
767
    } while ((node = node->next));
Karl Heyes's avatar
Karl Heyes committed
768
    if (relay->localmount == NULL)
769
        relay->localmount = (char *)xmlStrdup (XMLSTR(relay->mount));
770 771 772 773 774 775
}

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

778 779
    if (listener == NULL)
        return;
780 781
    listener->port = 8000;

782 783 784 785
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

786
        if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
787 788 789 790 791 792
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            if(configuration->port == 0)
                configuration->port = atoi(tmp);
            listener->port = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
793
        else if (xmlStrcmp (node->name, XMLSTR("ssl")) == 0) {
794 795 796 797
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            listener->ssl = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
798
        else if (xmlStrcmp (node->name, XMLSTR("shoutcast-compat")) == 0) {
799 800 801 802
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            listener->shoutcast_compat = atoi(tmp);
            if(tmp) xmlFree(tmp);
        }
803
        else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
804 805 806 807
            listener->bind_address = (char *)xmlNodeListGetString(doc, 
                    node->xmlChildrenNode, 1);
        }
    } while ((node = node->next));
808 809 810 811

    listener->next = configuration->listen_sock;
    configuration->listen_sock = listener;
    configuration->listen_sock_count++;
812 813 814 815 816 817 818 819 820
}

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

821
        if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
822
            char *mount, *pass;
823
            if ((mount = (char *)xmlGetProp(node, XMLSTR("mount"))) != NULL) {
824 825 826 827
                pass = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
                /* FIXME: This is a placeholder for per-mount passwords */
            }
            else {
828
                if (configuration->source_password)
829 830 831 832
                    xmlFree(configuration->source_password);
                configuration->source_password = 
                    (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            }
833
        } else if (xmlStrcmp (node->name, XMLSTR("admin-password")) == 0) {
834 835 836 837
            if(configuration->admin_password)
                xmlFree(configuration->admin_password);
            configuration->admin_password =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
838
        } else if (xmlStrcmp (node->name, XMLSTR("admin-user")) == 0) {
839 840 841 842
            if(configuration->admin_username)
                xmlFree(configuration->admin_username);
            configuration->admin_username =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
843
        } else if (xmlStrcmp (node->name, XMLSTR("relay-password")) == 0) {
844 845 846 847
            if(configuration->relay_password)
                xmlFree(configuration->relay_password);
            configuration->relay_password =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
848
        } else if (xmlStrcmp (node->name, XMLSTR("relay-user")) == 0) {
849 850 851 852
            if(configuration->relay_username)
                xmlFree(configuration->relay_username);
            configuration->relay_username =
                (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
        }
    } while ((node = node->next));
}

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

    if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) {
        ERROR0("Maximum number of yp directories exceeded!");
        return;
    }
    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

870
        if (xmlStrcmp (node->name, XMLSTR("yp-url")) == 0) {
871 872 873 874
            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);
875
        } else if (xmlStrcmp (node->name, XMLSTR("yp-url-timeout")) == 0) {
876 877 878
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            configuration->yp_url_timeout[configuration->num_yp_directories] = 
                atoi(tmp);
Karl Heyes's avatar
Karl Heyes committed
879
            if (tmp) xmlFree(tmp);
880
        } else if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
881
            _add_server(doc, node->xmlChildrenNode, configuration);
882
        } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) {
883
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
884 885
            configuration->yp_touch_interval[configuration->num_yp_directories] =
                atoi(tmp);
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
            if (tmp) xmlFree(tmp);
        }
    } while ((node = node->next));
    configuration->num_yp_directories++;
}

static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
        ice_config_t *configuration)
{
    char *temp;
    aliases *alias, *current, *last;

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

902
        if (xmlStrcmp (node->name, XMLSTR("basedir")) == 0) {
903
            if (configuration->base_dir) xmlFree(configuration->base_dir);
904
            configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
905
        } else if (xmlStrcmp (node->name, XMLSTR("logdir")) == 0) {
906
            if (configuration->log_dir) xmlFree(configuration->log_dir);
907
            configuration->log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
908
        } else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) {
909 910
            if (configuration->pidfile) xmlFree(configuration->pidfile);
            configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
911 912 913 914 915 916
        } 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);
917
        } else if (xmlStrcmp (node->name, XMLSTR("ssl-certificate")) == 0) {
918 919
            if (configuration->cert_file) xmlFree(configuration->cert_file);
            configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
920
        } else if (xmlStrcmp (node->name, XMLSTR("webroot")) == 0) {
921
            if (configuration->webroot_dir) xmlFree(configuration->webroot_dir);
922 923 924
            configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
                configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
925
        } else if (xmlStrcmp (node->name, XMLSTR("adminroot")) == 0) {
926
            if (configuration->adminroot_dir) 
927 928 929 930
                xmlFree(configuration->adminroot_dir);
            configuration->adminroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
            if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
                configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
931
        } else if (xmlStrcmp (node->name, XMLSTR("alias")) == 0) {
932 933
            alias = malloc(sizeof(aliases));
            alias->next = NULL;
934
            alias->source = (char *)xmlGetProp(node, XMLSTR("source"));
935 936 937 938
            if(alias->source == NULL) {
                free(alias);
                continue;
            }
939
            alias->destination = (char *)xmlGetProp(node, XMLSTR("dest"));
940 941 942 943 944 945
            if(alias->destination == NULL) {
                xmlFree(alias->source);
                free(alias);
                continue;
            }
            temp = NULL;
946
            temp = (char *)xmlGetProp(node, XMLSTR("port"));
947 948 949 950 951 952
            if(temp != NULL) {
                alias->port = atoi(temp);
                xmlFree(temp);
            }
            else
                alias->port = -1;
953
            alias->