1 /* Icecast
2 *
3 * This program is distributed under the GNU General Public License, version 2.
4 * A copy of this license is included with this source.
5 *
6 * Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
7 * Michael Smith <msmith@xiph.org>,
8 * oddsock <oddsock@xiph.org>,
9 * Karl Heyes <karl@xiph.org>
10 * and others (see AUTHORS for details).
11 * Copyright 2011, Dave 'justdave' Miller <justdave@mozilla.com>.
12 * 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 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #ifndef _WIN32
24 #include <fnmatch.h>
25 #endif
26 #include <libxml/xmlmemory.h>
27 #include <libxml/parser.h>
28
29 #include "thread/thread.h"
30 #include "cfgfile.h"
31 #include "refbuf.h"
32 #include "client.h"
33 #include "logging.h"
34
35 #define CATMODULE "CONFIG"
36 #define CONFIG_DEFAULT_LOCATION "Earth"
37 #define CONFIG_DEFAULT_ADMIN "icemaster@localhost"
38 #define CONFIG_DEFAULT_CLIENT_LIMIT 256
39 #define CONFIG_DEFAULT_SOURCE_LIMIT 16
40 #define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (500*1024)
41 #define CONFIG_DEFAULT_BURST_SIZE (64*1024)
42 #define CONFIG_DEFAULT_THREADPOOL_SIZE 4
43 #define CONFIG_DEFAULT_CLIENT_TIMEOUT 30
44 #define CONFIG_DEFAULT_HEADER_TIMEOUT 15
45 #define CONFIG_DEFAULT_SOURCE_TIMEOUT 10
46 #define CONFIG_DEFAULT_MASTER_USERNAME "relay"
47 #define CONFIG_DEFAULT_SHOUTCAST_MOUNT "/stream"
48 #define CONFIG_DEFAULT_ICE_LOGIN 0
49 #define CONFIG_DEFAULT_FILESERVE 1
50 #define CONFIG_DEFAULT_TOUCH_FREQ 5
51 #define CONFIG_DEFAULT_HOSTNAME "localhost"
52 #define CONFIG_DEFAULT_PLAYLIST_LOG NULL
53 #define CONFIG_DEFAULT_ACCESS_LOG "access.log"
54 #define CONFIG_DEFAULT_ERROR_LOG "error.log"
55 #define CONFIG_DEFAULT_LOG_LEVEL 3
56 #define CONFIG_DEFAULT_CHROOT 0
57 #define CONFIG_DEFAULT_CHUID 0
58 #define CONFIG_DEFAULT_USER NULL
59 #define CONFIG_DEFAULT_GROUP NULL
60 #define CONFIG_MASTER_UPDATE_INTERVAL 120
61 #define CONFIG_YP_URL_TIMEOUT 10
62 #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"
63
64 #ifndef _WIN32
65 #define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast"
66 #define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs"
67 #define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot"
68 #define CONFIG_DEFAULT_ADMINROOT_DIR "/usr/local/icecast/admin"
69 #define MIMETYPESFILE "/etc/mime.types"
70 #else
71 #define CONFIG_DEFAULT_BASE_DIR ".\\"
72 #define CONFIG_DEFAULT_LOG_DIR ".\\logs"
73 #define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot"
74 #define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin"
75 #define MIMETYPESFILE ".\\mime.types"
76 #endif
77
78 static ice_config_t _current_configuration;
79 static ice_config_locks _locks;
80
81 static void _set_defaults(ice_config_t *c);
82 static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
83 static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
84 static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
85 static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
86 static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
87 static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
88 static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
89 ice_config_t *c);
90 static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node,
91 ice_config_http_header_t **http_headers);
92 static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
93 static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
94 static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
95 ice_config_t *c);
96 static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
97
98 static void merge_mounts(mount_proxy * dst, mount_proxy * src);
99 static inline void _merge_mounts_all(ice_config_t *c);
100
create_locks(void)101 static void create_locks(void) {
102 thread_mutex_create(&_locks.relay_lock);
103 thread_rwlock_create(&_locks.config_lock);
104 }
105
release_locks(void)106 static void release_locks(void) {
107 thread_mutex_destroy(&_locks.relay_lock);
108 thread_rwlock_destroy(&_locks.config_lock);
109 }
110
config_initialize(void)111 void config_initialize(void) {
112 create_locks();
113 }
114
config_shutdown(void)115 void config_shutdown(void) {
116 config_get_config();
117 config_clear(&_current_configuration);
118 config_release_config();
119 release_locks();
120 }
121
config_init_configuration(ice_config_t * configuration)122 void config_init_configuration(ice_config_t *configuration)
123 {
124 memset(configuration, 0, sizeof(ice_config_t));
125 _set_defaults(configuration);
126 }
127
config_clear_http_header(ice_config_http_header_t * header)128 static void config_clear_http_header(ice_config_http_header_t *header) {
129 ice_config_http_header_t *old;
130
131 while (header) {
132 xmlFree(header->name);
133 xmlFree(header->value);
134 old = header;
135 header = header->next;
136 free(old);
137 }
138 }
139
config_copy_http_header(ice_config_http_header_t * header)140 static inline ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) {
141 ice_config_http_header_t *ret = NULL;
142 ice_config_http_header_t *cur = NULL;
143 ice_config_http_header_t *old = NULL;
144
145 while (header) {
146 if (cur) {
147 cur->next = calloc(1, sizeof(ice_config_http_header_t));
148 old = cur;
149 cur = cur->next;
150 } else {
151 ret = calloc(1, sizeof(ice_config_http_header_t));
152 cur = ret;
153 }
154
155 if (!cur) return ret; /* TODO: do better error handling */
156
157 cur->type = header->type;
158 cur->name = (char *)xmlCharStrdup(header->name);
159 cur->value = (char *)xmlCharStrdup(header->value);
160 cur->status = header->status;
161
162 if (!cur->name || !cur->value) {
163 if (cur->name) xmlFree(cur->name);
164 if (cur->value) xmlFree(cur->value);
165 if (old) {
166 old->next = NULL;
167 } else {
168 ret = NULL;
169 }
170 free(cur);
171 return ret;
172 }
173
174 header = header->next;
175 }
176
177 return ret;
178 }
179
config_clear_mount(mount_proxy * mount)180 static void config_clear_mount (mount_proxy *mount)
181 {
182 config_options_t *option;
183
184 if (mount->mountname) xmlFree (mount->mountname);
185 if (mount->username) xmlFree (mount->username);
186 if (mount->password) xmlFree (mount->password);
187 if (mount->dumpfile) xmlFree (mount->dumpfile);
188 if (mount->intro_filename) xmlFree (mount->intro_filename);
189 if (mount->on_connect) xmlFree (mount->on_connect);
190 if (mount->on_disconnect) xmlFree (mount->on_disconnect);
191 if (mount->fallback_mount) xmlFree (mount->fallback_mount);
192 if (mount->stream_name) xmlFree (mount->stream_name);
193 if (mount->stream_description) xmlFree (mount->stream_description);
194 if (mount->stream_url) xmlFree (mount->stream_url);
195 if (mount->stream_genre) xmlFree (mount->stream_genre);
196 if (mount->bitrate) xmlFree (mount->bitrate);
197 if (mount->type) xmlFree (mount->type);
198 if (mount->charset) xmlFree (mount->charset);
199 if (mount->cluster_password) xmlFree (mount->cluster_password);
200
201 if (mount->auth_type) xmlFree (mount->auth_type);
202 option = mount->auth_options;
203 while (option)
204 {
205 config_options_t *nextopt = option->next;
206 if (option->name) xmlFree (option->name);
207 if (option->value) xmlFree (option->value);
208 free (option);
209 option = nextopt;
210 }
211 auth_release (mount->auth);
212 config_clear_http_header(mount->http_headers);
213 free (mount);
214 }
215
config_clear_listener(listener_t * listener)216 listener_t *config_clear_listener (listener_t *listener)
217 {
218 listener_t *next = NULL;
219 if (listener)
220 {
221 next = listener->next;
222 if (listener->bind_address) xmlFree (listener->bind_address);
223 if (listener->shoutcast_mount) xmlFree (listener->shoutcast_mount);
224 free (listener);
225 }
226 return next;
227 }
228
config_clear(ice_config_t * c)229 void config_clear(ice_config_t *c)
230 {
231 ice_config_dir_t *dirnode, *nextdirnode;
232 relay_server *relay, *nextrelay;
233 mount_proxy *mount, *nextmount;
234 aliases *alias, *nextalias;
235 #ifdef USE_YP
236 int i;
237 #endif
238
239 free(c->config_filename);
240
241 xmlFree (c->server_id);
242 if (c->location) xmlFree(c->location);
243 if (c->admin) xmlFree(c->admin);
244 if (c->source_password) xmlFree(c->source_password);
245 if (c->admin_username)
246 xmlFree(c->admin_username);
247 if (c->admin_password)
248 xmlFree(c->admin_password);
249 if (c->relay_username)
250 xmlFree(c->relay_username);
251 if (c->relay_password)
252 xmlFree(c->relay_password);
253 if (c->hostname) xmlFree(c->hostname);
254 if (c->base_dir) xmlFree(c->base_dir);
255 if (c->log_dir) xmlFree(c->log_dir);
256 if (c->webroot_dir) xmlFree(c->webroot_dir);
257 if (c->adminroot_dir) xmlFree(c->adminroot_dir);
258 if (c->cert_file) xmlFree(c->cert_file);
259 if (c->cipher_list) xmlFree(c->cipher_list);
260 if (c->pidfile)
261 xmlFree(c->pidfile);
262 if (c->banfile) xmlFree(c->banfile);
263 if (c->allowfile) xmlFree(c->allowfile);
264 if (c->playlist_log) xmlFree(c->playlist_log);
265 if (c->access_log) xmlFree(c->access_log);
266 if (c->error_log) xmlFree(c->error_log);
267 if (c->shoutcast_mount) xmlFree(c->shoutcast_mount);
268 if (c->master_server) xmlFree(c->master_server);
269 if (c->master_username) xmlFree(c->master_username);
270 if (c->master_password) xmlFree(c->master_password);
271 if (c->user) xmlFree(c->user);
272 if (c->group) xmlFree(c->group);
273 if (c->mimetypes_fn) xmlFree (c->mimetypes_fn);
274
275 while ((c->listen_sock = config_clear_listener (c->listen_sock)))
276 ;
277
278 thread_mutex_lock(&(_locks.relay_lock));
279 relay = c->relay;
280 while(relay) {
281 nextrelay = relay->next;
282 xmlFree(relay->server);
283 xmlFree(relay->mount);
284 xmlFree(relay->localmount);
285 free(relay);
286 relay = nextrelay;
287 }
288 thread_mutex_unlock(&(_locks.relay_lock));
289
290 mount = c->mounts;
291 while(mount) {
292 nextmount = mount->next;
293 config_clear_mount (mount);
294 mount = nextmount;
295 }
296
297 alias = c->aliases;
298 while(alias) {
299 nextalias = alias->next;
300 xmlFree(alias->source);
301 xmlFree(alias->destination);
302 xmlFree(alias->bind_address);
303 free(alias);
304 alias = nextalias;
305 }
306
307 dirnode = c->dir_list;
308 while(dirnode) {
309 nextdirnode = dirnode->next;
310 xmlFree(dirnode->host);
311 free(dirnode);
312 dirnode = nextdirnode;
313 }
314 #ifdef USE_YP
315 i = 0;
316 while (i < c->num_yp_directories)
317 {
318 xmlFree (c->yp_url[i]);
319 i++;
320 }
321 #endif
322
323 config_clear_http_header(c->http_headers);
324
325 memset(c, 0, sizeof(ice_config_t));
326 }
327
config_initial_parse_file(const char * filename)328 int config_initial_parse_file(const char *filename)
329 {
330 /* Since we're already pointing at it, we don't need to copy it in place */
331 return config_parse_file(filename, &_current_configuration);
332 }
333
config_parse_file(const char * filename,ice_config_t * configuration)334 int config_parse_file(const char *filename, ice_config_t *configuration)
335 {
336 xmlDocPtr doc;
337 xmlNodePtr node;
338
339 if (filename == NULL || strcmp(filename, "") == 0) return CONFIG_EINSANE;
340
341 doc = xmlParseFile(filename);
342 if (doc == NULL) {
343 return CONFIG_EPARSE;
344 }
345
346 node = xmlDocGetRootElement(doc);
347 if (node == NULL) {
348 xmlFreeDoc(doc);
349 return CONFIG_ENOROOT;
350 }
351
352 if (xmlStrcmp (node->name, XMLSTR("icecast")) != 0) {
353 xmlFreeDoc(doc);
354 return CONFIG_EBADROOT;
355 }
356
357 config_init_configuration(configuration);
358
359 configuration->config_filename = strdup (filename);
360
361 _parse_root(doc, node->xmlChildrenNode, configuration);
362
363 xmlFreeDoc(doc);
364
365 _merge_mounts_all(configuration);
366
367 return 0;
368 }
369
config_parse_cmdline(int arg,char ** argv)370 int config_parse_cmdline(int arg, char **argv)
371 {
372 return 0;
373 }
374
config_locks(void)375 ice_config_locks *config_locks(void)
376 {
377 return &_locks;
378 }
379
config_release_config(void)380 void config_release_config(void)
381 {
382 thread_rwlock_unlock(&(_locks.config_lock));
383 }
384
config_get_config(void)385 ice_config_t *config_get_config(void)
386 {
387 thread_rwlock_rlock(&(_locks.config_lock));
388 return &_current_configuration;
389 }
390
config_grab_config(void)391 ice_config_t *config_grab_config(void)
392 {
393 thread_rwlock_wlock(&(_locks.config_lock));
394 return &_current_configuration;
395 }
396
397 /* MUST be called with the lock held! */
config_set_config(ice_config_t * config)398 void config_set_config(ice_config_t *config) {
399 memcpy(&_current_configuration, config, sizeof(ice_config_t));
400 }
401
config_get_config_unlocked(void)402 ice_config_t *config_get_config_unlocked(void)
403 {
404 return &_current_configuration;
405 }
406
_set_defaults(ice_config_t * configuration)407 static void _set_defaults(ice_config_t *configuration)
408 {
409 configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
410 configuration->server_id = (char *)xmlCharStrdup (ICECAST_VERSION_STRING);
411 configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN);
412 configuration->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT;
413 configuration->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT;
414 configuration->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT;
415 configuration->threadpool_size = CONFIG_DEFAULT_THREADPOOL_SIZE;
416 configuration->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT;
417 configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
418 configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
419 configuration->source_password = NULL;
420 configuration->shoutcast_mount = (char *)xmlCharStrdup (CONFIG_DEFAULT_SHOUTCAST_MOUNT);
421 configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
422 configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
423 configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
424 configuration->on_demand = 0;
425 configuration->dir_list = NULL;
426 configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
427 configuration->mimetypes_fn = (char *)xmlCharStrdup (MIMETYPESFILE);
428 configuration->master_server = NULL;
429 configuration->master_server_port = 0;
430 configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
431 configuration->master_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
432 configuration->master_password = NULL;
433 configuration->base_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_BASE_DIR);
434 configuration->log_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOG_DIR);
435 configuration->cipher_list = (char *)xmlCharStrdup (CONFIG_DEFAULT_CIPHER_LIST);
436 configuration->webroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_WEBROOT_DIR);
437 configuration->adminroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMINROOT_DIR);
438 configuration->playlist_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_PLAYLIST_LOG);
439 configuration->access_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ACCESS_LOG);
440 configuration->error_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ERROR_LOG);
441 configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
442 configuration->chroot = CONFIG_DEFAULT_CHROOT;
443 configuration->chuid = CONFIG_DEFAULT_CHUID;
444 configuration->user = NULL;
445 configuration->group = NULL;
446 configuration->num_yp_directories = 0;
447 configuration->relay_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
448 configuration->relay_password = NULL;
449 /* default to a typical prebuffer size used by clients */
450 configuration->burst_size = CONFIG_DEFAULT_BURST_SIZE;
451 }
452
_parse_root(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)453 static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
454 ice_config_t *configuration)
455 {
456 char *tmp;
457
458 configuration->listen_sock = calloc (1, sizeof (*configuration->listen_sock));
459 configuration->listen_sock->port = 8000;
460 configuration->listen_sock_count = 1;
461
462 do {
463 if (node == NULL) break;
464 if (xmlIsBlankNode(node)) continue;
465
466 if (xmlStrcmp (node->name, XMLSTR("location")) == 0) {
467 if (configuration->location) xmlFree(configuration->location);
468 configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
469 } else if (xmlStrcmp (node->name, XMLSTR("admin")) == 0) {
470 if (configuration->admin) xmlFree(configuration->admin);
471 configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
472 } else if (xmlStrcmp (node->name, XMLSTR("server-id")) == 0) {
473 xmlFree (configuration->server_id);
474 configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
475 ICECAST_LOG_WARN("Warning, server version string override detected. This may lead to unexpected client software behavior.");
476 } else if(xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
477 _parse_authentication(doc, node->xmlChildrenNode, configuration);
478 } else if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
479 /* TODO: This is the backwards-compatibility location */
480 ICECAST_LOG_WARN("<source-password> defined outside <authentication>. This is deprecated.");
481 if (configuration->source_password) xmlFree(configuration->source_password);
482 configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
483 } else if (xmlStrcmp (node->name, XMLSTR("icelogin")) == 0) {
484 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
485 configuration->ice_login = atoi(tmp);
486 if (tmp) xmlFree(tmp);
487 } else if (xmlStrcmp (node->name, XMLSTR("fileserve")) == 0) {
488 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
489 configuration->fileserve = atoi(tmp);
490 if (tmp) xmlFree(tmp);
491 } else if (xmlStrcmp (node->name, XMLSTR("relays-on-demand")) == 0) {
492 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
493 configuration->on_demand = atoi(tmp);
494 if (tmp) xmlFree(tmp);
495 } else if (xmlStrcmp (node->name, XMLSTR("hostname")) == 0) {
496 if (configuration->hostname) xmlFree(configuration->hostname);
497 configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
498 } else if (xmlStrcmp (node->name, XMLSTR("mime-types")) == 0) {
499 if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn);
500 configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
501 } else if (xmlStrcmp (node->name, XMLSTR("listen-socket")) == 0) {
502 _parse_listen_socket(doc, node->xmlChildrenNode, configuration);
503 } else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
504 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
505 if (tmp) {
506 configuration->port = atoi(tmp);
507 configuration->listen_sock->port = atoi(tmp);
508 xmlFree(tmp);
509 } else {
510 ICECAST_LOG_WARN("<port> must not be empty.");
511 }
512 } else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
513 if (configuration->listen_sock->bind_address)
514 xmlFree(configuration->listen_sock->bind_address);
515 configuration->listen_sock->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
516 } else if (xmlStrcmp (node->name, XMLSTR("master-server")) == 0) {
517 if (configuration->master_server) xmlFree(configuration->master_server);
518 configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
519 } else if (xmlStrcmp (node->name, XMLSTR("master-username")) == 0) {
520 if (configuration->master_username) xmlFree(configuration->master_username);
521 configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
522 } else if (xmlStrcmp (node->name, XMLSTR("master-password")) == 0) {
523 if (configuration->master_password) xmlFree(configuration->master_password);
524 configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
525 } else if (xmlStrcmp (node->name, XMLSTR("master-server-port")) == 0) {
526 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
527 configuration->master_server_port = atoi(tmp);
528 xmlFree (tmp);
529 } else if (xmlStrcmp (node->name, XMLSTR("master-update-interval")) == 0) {
530 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
531 configuration->master_update_interval = atoi(tmp);
532 xmlFree (tmp);
533 } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
534 if (configuration->shoutcast_mount) xmlFree(configuration->shoutcast_mount);
535 configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
536 } else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
537 _parse_limits(doc, node->xmlChildrenNode, configuration);
538 } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
539 _parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers));
540 } else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
541 _parse_relay(doc, node->xmlChildrenNode, configuration);
542 } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
543 _parse_mount(doc, node, configuration);
544 } else if (xmlStrcmp (node->name, XMLSTR("directory")) == 0) {
545 _parse_directory(doc, node->xmlChildrenNode, configuration);
546 } else if (xmlStrcmp (node->name, XMLSTR("paths")) == 0) {
547 _parse_paths(doc, node->xmlChildrenNode, configuration);
548 } else if (xmlStrcmp (node->name, XMLSTR("logging")) == 0) {
549 _parse_logging(doc, node->xmlChildrenNode, configuration);
550 } else if (xmlStrcmp (node->name, XMLSTR("security")) == 0) {
551 _parse_security(doc, node->xmlChildrenNode, configuration);
552 }
553 } while ((node = node->next));
554
555 /* drop the first listening socket details if more than one is defined, as we only
556 * have port or listen-socket not both */
557 if (configuration->listen_sock_count > 1)
558 {
559 configuration->listen_sock = config_clear_listener (configuration->listen_sock);
560 configuration->listen_sock_count--;
561 }
562 if (configuration->port == 0)
563 configuration->port = 8000;
564
565 /* issue some warnings on bad configurations */
566 if (!configuration->fileserve)
567 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).");
568
569 if (!configuration->hostname || strcmp(configuration->hostname, CONFIG_DEFAULT_HOSTNAME) == 0) {
570 ICECAST_LOG_WARN("Warning, <hostname> not configured, using default value \"%s\". This will cause problems, e.g. with YP directory listings.", CONFIG_DEFAULT_HOSTNAME);
571 if (!configuration->hostname)
572 configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
573 }
574
575 if (!configuration->location || strcmp(configuration->location, CONFIG_DEFAULT_LOCATION) == 0) {
576 ICECAST_LOG_WARN("Warning, <location> not configured, using default value \"%s\".", CONFIG_DEFAULT_LOCATION);
577 if (!configuration->location)
578 configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
579 }
580
581 if (!configuration->admin || strcmp(configuration->admin, CONFIG_DEFAULT_ADMIN) == 0) {
582 ICECAST_LOG_WARN("Warning, <admin> contact not configured, using default value \"%s\".", CONFIG_DEFAULT_ADMIN);
583 if (!configuration->admin)
584 configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN);
585 }
586 }
587
_parse_limits(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)588 static void _parse_limits(xmlDocPtr doc, xmlNodePtr node,
589 ice_config_t *configuration)
590 {
591 char *tmp;
592
593 do {
594 if (node == NULL) break;
595 if (xmlIsBlankNode(node)) continue;
596
597 if (xmlStrcmp (node->name, XMLSTR("clients")) == 0) {
598 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
599 configuration->client_limit = atoi(tmp);
600 if (tmp) xmlFree(tmp);
601 } else if (xmlStrcmp (node->name, XMLSTR("sources")) == 0) {
602 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
603 configuration->source_limit = atoi(tmp);
604 if (tmp) xmlFree(tmp);
605 } else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
606 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
607 configuration->queue_size_limit = atoi(tmp);
608 if (tmp) xmlFree(tmp);
609 } else if (xmlStrcmp (node->name, XMLSTR("threadpool")) == 0) {
610 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
611 configuration->threadpool_size = atoi(tmp);
612 if (tmp) xmlFree(tmp);
613 } else if (xmlStrcmp (node->name, XMLSTR("client-timeout")) == 0) {
614 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
615 configuration->client_timeout = atoi(tmp);
616 if (tmp) xmlFree(tmp);
617 } else if (xmlStrcmp (node->name, XMLSTR("header-timeout")) == 0) {
618 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
619 configuration->header_timeout = atoi(tmp);
620 if (tmp) xmlFree(tmp);
621 } else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
622 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
623 configuration->source_timeout = atoi(tmp);
624 if (tmp) xmlFree(tmp);
625 } else if (xmlStrcmp (node->name, XMLSTR("burst-on-connect")) == 0) {
626 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
627 if (atoi(tmp) == 0)
628 configuration->burst_size = 0;
629 if (tmp) xmlFree(tmp);
630 } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
631 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
632 configuration->burst_size = atoi(tmp);
633 if (tmp) xmlFree(tmp);
634 }
635 } while ((node = node->next));
636 }
637
_parse_mount(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)638 static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
639 ice_config_t *configuration)
640 {
641 char *tmp;
642 mount_proxy *mount = calloc(1, sizeof(mount_proxy));
643 mount_proxy *current = configuration->mounts;
644 mount_proxy *last=NULL;
645
646 /* default <mount> settings */
647 mount->mounttype = MOUNT_TYPE_NORMAL;
648 mount->max_listeners = -1;
649 mount->burst_size = -1;
650 mount->mp3_meta_interval = -1;
651 mount->yp_public = -1;
652 mount->next = NULL;
653
654 tmp = (char *)xmlGetProp(node, XMLSTR("type"));
655 if (tmp) {
656 if (strcmp(tmp, "normal") == 0) {
657 mount->mounttype = MOUNT_TYPE_NORMAL;
658 }
659 else if (strcmp(tmp, "default") == 0) {
660 mount->mounttype = MOUNT_TYPE_DEFAULT;
661 }
662 else {
663 ICECAST_LOG_WARN("Unknown mountpoint type: %s", tmp);
664 config_clear_mount (mount);
665 return;
666 }
667 xmlFree(tmp);
668 }
669
670 node = node->xmlChildrenNode;
671
672 do {
673 if (node == NULL) break;
674 if (xmlIsBlankNode(node)) continue;
675
676 if (xmlStrcmp (node->name, XMLSTR("mount-name")) == 0) {
677 mount->mountname = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
678 }
679 else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
680 mount->username = (char *)xmlNodeListGetString(
681 doc, node->xmlChildrenNode, 1);
682 }
683 else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
684 mount->password = (char *)xmlNodeListGetString(
685 doc, node->xmlChildrenNode, 1);
686 }
687 else if (xmlStrcmp (node->name, XMLSTR("dump-file")) == 0) {
688 mount->dumpfile = (char *)xmlNodeListGetString(
689 doc, node->xmlChildrenNode, 1);
690 }
691 else if (xmlStrcmp (node->name, XMLSTR("intro")) == 0) {
692 mount->intro_filename = (char *)xmlNodeListGetString(
693 doc, node->xmlChildrenNode, 1);
694 }
695 else if (xmlStrcmp (node->name, XMLSTR("fallback-mount")) == 0) {
696 mount->fallback_mount = (char *)xmlNodeListGetString(
697 doc, node->xmlChildrenNode, 1);
698 }
699 else if (xmlStrcmp (node->name, XMLSTR("fallback-when-full")) == 0) {
700 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
701 mount->fallback_when_full = atoi(tmp);
702 if(tmp) xmlFree(tmp);
703 }
704 else if (xmlStrcmp (node->name, XMLSTR("max-listeners")) == 0) {
705 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
706 mount->max_listeners = atoi(tmp);
707 if(tmp) xmlFree(tmp);
708 }
709 else if (xmlStrcmp (node->name, XMLSTR("charset")) == 0) {
710 mount->charset = (char *)xmlNodeListGetString(doc,
711 node->xmlChildrenNode, 1);
712 }
713 else if (xmlStrcmp (node->name, XMLSTR("mp3-metadata-interval")) == 0) {
714 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
715 mount->mp3_meta_interval = atoi(tmp);
716 if(tmp) xmlFree(tmp);
717 }
718 else if (xmlStrcmp (node->name, XMLSTR("fallback-override")) == 0) {
719 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
720 mount->fallback_override = atoi(tmp);
721 if(tmp) xmlFree(tmp);
722 }
723 else if (xmlStrcmp (node->name, XMLSTR("no-mount")) == 0) {
724 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
725 mount->no_mount = atoi(tmp);
726 if(tmp) xmlFree(tmp);
727 }
728 else if (xmlStrcmp (node->name, XMLSTR("no-yp")) == 0) {
729 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
730 mount->yp_public = atoi(tmp) == 0 ? -1 : 0;
731 if(tmp) xmlFree(tmp);
732 }
733 else if (xmlStrcmp (node->name, XMLSTR("hidden")) == 0) {
734 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
735 mount->hidden = atoi(tmp);
736 if(tmp) xmlFree(tmp);
737 }
738 else if (xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
739 mount->auth = auth_get_authenticator (node);
740 }
741 else if (xmlStrcmp (node->name, XMLSTR("on-connect")) == 0) {
742 mount->on_connect = (char *)xmlNodeListGetString(
743 doc, node->xmlChildrenNode, 1);
744 }
745 else if (xmlStrcmp (node->name, XMLSTR("on-disconnect")) == 0) {
746 mount->on_disconnect = (char *)xmlNodeListGetString(
747 doc, node->xmlChildrenNode, 1);
748 }
749 else if (xmlStrcmp (node->name, XMLSTR("max-listener-duration")) == 0) {
750 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
751 mount->max_listener_duration = atoi(tmp);
752 if(tmp) xmlFree(tmp);
753 }
754 else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
755 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
756 mount->queue_size_limit = atoi (tmp);
757 if(tmp) xmlFree(tmp);
758 }
759 else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
760 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
761 if (tmp)
762 {
763 mount->source_timeout = atoi (tmp);
764 xmlFree(tmp);
765 }
766 } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
767 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
768 mount->burst_size = atoi(tmp);
769 if (tmp) xmlFree(tmp);
770 } else if (xmlStrcmp (node->name, XMLSTR("cluster-password")) == 0) {
771 mount->cluster_password = (char *)xmlNodeListGetString(
772 doc, node->xmlChildrenNode, 1);
773 } else if (xmlStrcmp (node->name, XMLSTR("stream-name")) == 0) {
774 mount->stream_name = (char *)xmlNodeListGetString(
775 doc, node->xmlChildrenNode, 1);
776 } else if (xmlStrcmp (node->name, XMLSTR("stream-description")) == 0) {
777 mount->stream_description = (char *)xmlNodeListGetString(
778 doc, node->xmlChildrenNode, 1);
779 } else if (xmlStrcmp (node->name, XMLSTR("stream-url")) == 0) {
780 mount->stream_url = (char *)xmlNodeListGetString(
781 doc, node->xmlChildrenNode, 1);
782 } else if (xmlStrcmp (node->name, XMLSTR("genre")) == 0) {
783 mount->stream_genre = (char *)xmlNodeListGetString(
784 doc, node->xmlChildrenNode, 1);
785 } else if (xmlStrcmp (node->name, XMLSTR("bitrate")) == 0) {
786 mount->bitrate = (char *)xmlNodeListGetString(
787 doc, node->xmlChildrenNode, 1);
788 } else if (xmlStrcmp (node->name, XMLSTR("public")) == 0) {
789 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
790 mount->yp_public = atoi (tmp);
791 if(tmp) xmlFree(tmp);
792 } else if (xmlStrcmp (node->name, XMLSTR("type")) == 0) {
793 mount->type = (char *)xmlNodeListGetString(
794 doc, node->xmlChildrenNode, 1);
795 } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
796 mount->subtype = (char *)xmlNodeListGetString(
797 doc, node->xmlChildrenNode, 1);
798 } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
799 _parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers));
800 }
801 } while ((node = node->next));
802
803 /* make sure we have at least the mountpoint name */
804 if (mount->mountname == NULL && mount->mounttype != MOUNT_TYPE_DEFAULT)
805 {
806 config_clear_mount (mount);
807 return;
808 }
809 else if (mount->mountname != NULL && mount->mounttype == MOUNT_TYPE_DEFAULT)
810 {
811 ICECAST_LOG_WARN("Default mount %s has mount-name set. This is not supported. Behavior may not be consistent.", mount->mountname);
812 }
813 if (mount->auth && mount->mountname) {
814 mount->auth->mount = strdup ((char *)mount->mountname);
815 } else if (mount->auth && mount->mounttype == MOUNT_TYPE_DEFAULT ) {
816 mount->auth->mount = strdup ("(default mount)");
817 }
818 while(current) {
819 last = current;
820 current = current->next;
821 }
822
823 if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override))
824 {
825 ICECAST_LOG_WARN("Config for mount %s contains fallback options but no fallback mount.", mount->mountname);
826 }
827
828 if(last)
829 last->next = mount;
830 else
831 configuration->mounts = mount;
832 }
833
_parse_http_headers(xmlDocPtr doc,xmlNodePtr node,ice_config_http_header_t ** http_headers)834 static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers) {
835 ice_config_http_header_t *header;
836 ice_config_http_header_t *next;
837 char *name = NULL;
838 char *value = NULL;
839 char *tmp;
840 int status;
841 http_header_type type;
842
843 do {
844 if (node == NULL) break;
845 if (xmlIsBlankNode(node)) continue;
846 if (xmlStrcmp (node->name, XMLSTR("header")) != 0) break;
847 if (!(name = (char *)xmlGetProp(node, XMLSTR("name")))) break;
848 if (!(value = (char *)xmlGetProp(node, XMLSTR("value")))) break;
849
850 type = HTTP_HEADER_TYPE_STATIC; /* default */
851 if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) {
852 if (strcmp(tmp, "static") == 0) {
853 type = HTTP_HEADER_TYPE_STATIC;
854 } else {
855 ICECAST_LOG_WARN("Unknown type %s for HTTP Header %s", tmp, name);
856 xmlFree(tmp);
857 break;
858 }
859 xmlFree(tmp);
860 }
861
862 status = 0; /* default: any */
863 if ((tmp = (char *)xmlGetProp(node, XMLSTR("status")))) {
864 status = atoi(tmp);
865 xmlFree(tmp);
866 }
867
868 header = calloc(1, sizeof(ice_config_http_header_t));
869 if (!header) break;
870 header->type = type;
871 header->name = name;
872 header->value = value;
873 header->status = status;
874 name = NULL;
875 value = NULL;
876
877 if (!*http_headers) {
878 *http_headers = header;
879 continue;
880 }
881 next = *http_headers;
882 while (next->next) next = next->next;
883 next->next = header;
884 } while ((node = node->next));
885 /* in case we used break we may need to clean those up */
886 if (name)
887 xmlFree(name);
888 if (value)
889 xmlFree(value);
890 }
891
_parse_relay(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)892 static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
893 ice_config_t *configuration)
894 {
895 char *tmp;
896 relay_server *relay = calloc(1, sizeof(relay_server));
897 relay_server *current = configuration->relay;
898 relay_server *last=NULL;
899
900 while(current) {
901 last = current;
902 current = current->next;
903 }
904
905 if(last)
906 last->next = relay;
907 else
908 configuration->relay = relay;
909
910 relay->next = NULL;
911 relay->mp3metadata = 1;
912 relay->on_demand = configuration->on_demand;
913 relay->server = (char *)xmlCharStrdup ("127.0.0.1");
914 relay->mount = (char *)xmlCharStrdup ("/");
915
916 do {
917 if (node == NULL) break;
918 if (xmlIsBlankNode(node)) continue;
919
920 if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
921 if (relay->server) xmlFree (relay->server);
922 relay->server = (char *)xmlNodeListGetString(
923 doc, node->xmlChildrenNode, 1);
924 }
925 else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
926 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
927 if (tmp) {
928 relay->port = atoi(tmp);
929 xmlFree(tmp);
930 } else {
931 ICECAST_LOG_WARN("<port> must not be empty.");
932 }
933 }
934 else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
935 if (relay->mount) xmlFree (relay->mount);
936 relay->mount = (char *)xmlNodeListGetString(
937 doc, node->xmlChildrenNode, 1);
938 }
939 else if (xmlStrcmp (node->name, XMLSTR("local-mount")) == 0) {
940 if (relay->localmount) xmlFree (relay->localmount);
941 relay->localmount = (char *)xmlNodeListGetString(
942 doc, node->xmlChildrenNode, 1);
943 }
944 else if (xmlStrcmp (node->name, XMLSTR("relay-shoutcast-metadata")) == 0) {
945 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
946 relay->mp3metadata = atoi(tmp);
947 if(tmp) xmlFree(tmp);
948 }
949 else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
950 if (relay->username) xmlFree (relay->username);
951 relay->username = (char *)xmlNodeListGetString(doc,
952 node->xmlChildrenNode, 1);
953 }
954 else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
955 if (relay->password) xmlFree (relay->password);
956 relay->password = (char *)xmlNodeListGetString(doc,
957 node->xmlChildrenNode, 1);
958 }
959 else if (xmlStrcmp (node->name, XMLSTR("on-demand")) == 0) {
960 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
961 relay->on_demand = atoi(tmp);
962 if (tmp) xmlFree(tmp);
963 }
964 else if (xmlStrcmp (node->name, XMLSTR("bind")) == 0) {
965 if (relay->bind) xmlFree (relay->bind);
966 relay->bind = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
967 }
968 } while ((node = node->next));
969 if (relay->localmount == NULL)
970 relay->localmount = (char *)xmlStrdup (XMLSTR(relay->mount));
971 }
972
_parse_listen_socket(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)973 static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
974 ice_config_t *configuration)
975 {
976 char *tmp;
977 listener_t *listener = calloc (1, sizeof(listener_t));
978
979 if (listener == NULL)
980 return;
981 listener->port = 8000;
982
983 do {
984 if (node == NULL) break;
985 if (xmlIsBlankNode(node)) continue;
986
987 if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
988 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
989 if (tmp) {
990 if(configuration->port == 0)
991 configuration->port = atoi(tmp);
992 listener->port = atoi(tmp);
993 xmlFree(tmp);
994 } else {
995 ICECAST_LOG_WARN("<port> must not be empty.");
996 }
997 }
998 else if (xmlStrcmp (node->name, XMLSTR("ssl")) == 0) {
999 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1000 listener->ssl = atoi(tmp);
1001 if(tmp) xmlFree(tmp);
1002 }
1003 else if (xmlStrcmp (node->name, XMLSTR("shoutcast-compat")) == 0) {
1004 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1005 listener->shoutcast_compat = atoi(tmp);
1006 if(tmp) xmlFree(tmp);
1007 }
1008 else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
1009 if (listener->shoutcast_mount) xmlFree (listener->shoutcast_mount);
1010 listener->shoutcast_mount = (char *)xmlNodeListGetString(doc,
1011 node->xmlChildrenNode, 1);
1012 }
1013 else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
1014 if (listener->bind_address) xmlFree (listener->bind_address);
1015 listener->bind_address = (char *)xmlNodeListGetString(doc,
1016 node->xmlChildrenNode, 1);
1017 }
1018 else if (xmlStrcmp (node->name, XMLSTR("so-sndbuf")) == 0) {
1019 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1020 listener->so_sndbuf = atoi(tmp);
1021 if(tmp) xmlFree(tmp);
1022 }
1023 } while ((node = node->next));
1024
1025 /* we know there's at least one of these, so add this new one after the first
1026 * that way it can be removed easily later on */
1027 listener->next = configuration->listen_sock->next;
1028 configuration->listen_sock->next = listener;
1029 configuration->listen_sock_count++;
1030 if (listener->shoutcast_mount)
1031 {
1032 listener_t *sc_port = calloc (1, sizeof (listener_t));
1033 sc_port->port = listener->port+1;
1034 sc_port->shoutcast_compat = 1;
1035 sc_port->shoutcast_mount = (char*)xmlStrdup (XMLSTR(listener->shoutcast_mount));
1036 if (listener->bind_address)
1037 sc_port->bind_address = (char*)xmlStrdup (XMLSTR(listener->bind_address));
1038
1039 sc_port->next = listener->next;
1040 listener->next = sc_port;
1041 configuration->listen_sock_count++;
1042 }
1043 }
1044
_parse_authentication(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1045 static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
1046 ice_config_t *configuration)
1047 {
1048 do {
1049 if (node == NULL) break;
1050 if (xmlIsBlankNode(node)) continue;
1051
1052 if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
1053 if (xmlGetProp(node, XMLSTR("mount"))) {
1054 ICECAST_LOG_ERROR("Mount level source password defined within global <authentication> section.");
1055 }
1056 else {
1057 if (configuration->source_password)
1058 xmlFree(configuration->source_password);
1059 configuration->source_password =
1060 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1061 }
1062 } else if (xmlStrcmp (node->name, XMLSTR("admin-password")) == 0) {
1063 if(configuration->admin_password)
1064 xmlFree(configuration->admin_password);
1065 configuration->admin_password =
1066 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1067 } else if (xmlStrcmp (node->name, XMLSTR("admin-user")) == 0) {
1068 if(configuration->admin_username)
1069 xmlFree(configuration->admin_username);
1070 configuration->admin_username =
1071 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1072 } else if (xmlStrcmp (node->name, XMLSTR("relay-password")) == 0) {
1073 if(configuration->relay_password)
1074 xmlFree(configuration->relay_password);
1075 configuration->relay_password =
1076 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1077 } else if (xmlStrcmp (node->name, XMLSTR("relay-user")) == 0) {
1078 if(configuration->relay_username)
1079 xmlFree(configuration->relay_username);
1080 configuration->relay_username =
1081 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1082 }
1083 } while ((node = node->next));
1084 }
1085
_parse_directory(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1086 static void _parse_directory(xmlDocPtr doc, xmlNodePtr node,
1087 ice_config_t *configuration)
1088 {
1089 char *tmp;
1090
1091 if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) {
1092 ICECAST_LOG_ERROR("Maximum number of yp directories exceeded!");
1093 return;
1094 }
1095 do {
1096 if (node == NULL) break;
1097 if (xmlIsBlankNode(node)) continue;
1098
1099 if (xmlStrcmp (node->name, XMLSTR("yp-url")) == 0) {
1100 if (configuration->yp_url[configuration->num_yp_directories])
1101 xmlFree(configuration->yp_url[configuration->num_yp_directories]);
1102 configuration->yp_url[configuration->num_yp_directories] =
1103 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1104 } else if (xmlStrcmp (node->name, XMLSTR("yp-url-timeout")) == 0) {
1105 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1106 configuration->yp_url_timeout[configuration->num_yp_directories] =
1107 atoi(tmp);
1108 if (tmp) xmlFree(tmp);
1109 } else if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
1110 _add_server(doc, node->xmlChildrenNode, configuration);
1111 } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) {
1112 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1113 configuration->yp_touch_interval[configuration->num_yp_directories] =
1114 atoi(tmp);
1115 if (tmp) xmlFree(tmp);
1116 }
1117 } while ((node = node->next));
1118 if (configuration->yp_url [configuration->num_yp_directories] == NULL)
1119 return;
1120 configuration->num_yp_directories++;
1121 }
1122
_parse_paths(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1123 static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
1124 ice_config_t *configuration)
1125 {
1126 char *temp;
1127 aliases *alias, *current, *last;
1128
1129 do {
1130 if (node == NULL) break;
1131 if (xmlIsBlankNode(node)) continue;
1132
1133 if (xmlStrcmp (node->name, XMLSTR("basedir")) == 0) {
1134 if (configuration->base_dir) xmlFree(configuration->base_dir);
1135 configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1136 } else if (xmlStrcmp (node->name, XMLSTR("logdir")) == 0) {
1137 if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1138 ICECAST_LOG_WARN("<logdir> must not be empty.");
1139 continue;
1140 }
1141 if (configuration->log_dir) xmlFree(configuration->log_dir);
1142 configuration->log_dir = temp;
1143 } else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) {
1144 if (configuration->pidfile) xmlFree(configuration->pidfile);
1145 configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1146 } else if (xmlStrcmp (node->name, XMLSTR("deny-ip")) == 0) {
1147 if (configuration->banfile) xmlFree(configuration->banfile);
1148 configuration->banfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1149 } else if (xmlStrcmp (node->name, XMLSTR("allow-ip")) == 0) {
1150 if (configuration->allowfile) xmlFree(configuration->allowfile);
1151 configuration->allowfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1152 } else if (xmlStrcmp (node->name, XMLSTR("ssl-certificate")) == 0) {
1153 if (configuration->cert_file) xmlFree(configuration->cert_file);
1154 configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1155 } else if (xmlStrcmp (node->name, XMLSTR("ssl-allowed-ciphers")) == 0) {
1156 if (configuration->cipher_list) xmlFree(configuration->cipher_list);
1157 configuration->cipher_list = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1158 } else if (xmlStrcmp (node->name, XMLSTR("webroot")) == 0) {
1159 if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1160 ICECAST_LOG_WARN("<webroot> must not be empty.");
1161 continue;
1162 }
1163 if (configuration->webroot_dir) xmlFree(configuration->webroot_dir);
1164 configuration->webroot_dir = temp;
1165 if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
1166 configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
1167 } else if (xmlStrcmp (node->name, XMLSTR("adminroot")) == 0) {
1168 if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1169 ICECAST_LOG_WARN("<adminroot> must not be empty.");
1170 continue;
1171 }
1172 if (configuration->adminroot_dir)
1173 xmlFree(configuration->adminroot_dir);
1174 configuration->adminroot_dir = (char *)temp;
1175 if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
1176 configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
1177 } else if (xmlStrcmp (node->name, XMLSTR("alias")) == 0) {
1178 alias = malloc(sizeof(aliases));
1179 alias->next = NULL;
1180 alias->source = (char *)xmlGetProp(node, XMLSTR("source"));
1181 if(alias->source == NULL) {
1182 free(alias);
1183 continue;
1184 }
1185 alias->destination = (char *)xmlGetProp(node, XMLSTR("destination"));
1186 if (!alias->destination)
1187 alias->destination = (char *)xmlGetProp(node, XMLSTR("dest"));
1188 if(alias->destination == NULL) {
1189 xmlFree(alias->source);
1190 free(alias);
1191 continue;
1192 }
1193 temp = NULL;
1194 temp = (char *)xmlGetProp(node, XMLSTR("port"));
1195 if(temp != NULL) {
1196 alias->port = atoi(temp);
1197 xmlFree(temp);
1198 }
1199 else
1200 alias->port = -1;
1201 alias->bind_address = (char *)xmlGetProp(node, XMLSTR("bind-address"));
1202 current = configuration->aliases;
1203 last = NULL;
1204 while(current) {
1205 last = current;
1206 current = current->next;
1207 }
1208 if(last)
1209 last->next = alias;
1210 else
1211 configuration->aliases = alias;
1212 }
1213 } while ((node = node->next));
1214 }
1215
_parse_logging(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1216 static void _parse_logging(xmlDocPtr doc, xmlNodePtr node,
1217 ice_config_t *configuration)
1218 {
1219 char *tmp;
1220 do {
1221 if (node == NULL) break;
1222 if (xmlIsBlankNode(node)) continue;
1223
1224 if (xmlStrcmp (node->name, XMLSTR("accesslog")) == 0) {
1225 if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1226 ICECAST_LOG_WARN("<accesslog> must not be empty.");
1227 continue;
1228 }
1229 if (configuration->access_log) xmlFree(configuration->access_log);
1230 configuration->access_log = tmp;
1231 } else if (xmlStrcmp (node->name, XMLSTR("errorlog")) == 0) {
1232 if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1233 ICECAST_LOG_WARN("<errorlog> must not be empty.");
1234 continue;
1235 }
1236 if (configuration->error_log) xmlFree(configuration->error_log);
1237 configuration->error_log = tmp;
1238 } else if (xmlStrcmp (node->name, XMLSTR("playlistlog")) == 0) {
1239 if (configuration->playlist_log) xmlFree(configuration->playlist_log);
1240 configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1241 } else if (xmlStrcmp (node->name, XMLSTR("logsize")) == 0) {
1242 char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1243 configuration->logsize = atoi(tmp);
1244 if (tmp) xmlFree(tmp);
1245 } else if (xmlStrcmp (node->name, XMLSTR("loglevel")) == 0) {
1246 char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1247 configuration->loglevel = atoi(tmp);
1248 if (tmp) xmlFree(tmp);
1249 } else if (xmlStrcmp (node->name, XMLSTR("logarchive")) == 0) {
1250 char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1251 configuration->logarchive = atoi(tmp);
1252 if (tmp) xmlFree(tmp);
1253 }
1254 } while ((node = node->next));
1255 }
1256
_parse_security(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1257 static void _parse_security(xmlDocPtr doc, xmlNodePtr node,
1258 ice_config_t *configuration)
1259 {
1260 char *tmp;
1261 xmlNodePtr oldnode;
1262
1263 do {
1264 if (node == NULL) break;
1265 if (xmlIsBlankNode(node)) continue;
1266
1267 if (xmlStrcmp (node->name, XMLSTR("chroot")) == 0) {
1268 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1269 configuration->chroot = atoi(tmp);
1270 if (tmp) xmlFree(tmp);
1271 } else if (xmlStrcmp (node->name, XMLSTR("changeowner")) == 0) {
1272 configuration->chuid = 1;
1273 oldnode = node;
1274 node = node->xmlChildrenNode;
1275 do {
1276 if(node == NULL) break;
1277 if(xmlIsBlankNode(node)) continue;
1278 if(xmlStrcmp (node->name, XMLSTR("user")) == 0) {
1279 if(configuration->user) xmlFree(configuration->user);
1280 configuration->user = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1281 } else if(xmlStrcmp (node->name, XMLSTR("group")) == 0) {
1282 if(configuration->group) xmlFree(configuration->group);
1283 configuration->group = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1284 }
1285 } while((node = node->next));
1286 node = oldnode;
1287 }
1288 } while ((node = node->next));
1289 }
1290
_add_server(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1291 static void _add_server(xmlDocPtr doc, xmlNodePtr node,
1292 ice_config_t *configuration)
1293 {
1294 ice_config_dir_t *dirnode, *server;
1295 int addnode;
1296 char *tmp;
1297
1298 server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t));
1299 server->touch_interval = configuration->touch_interval;
1300 server->host = NULL;
1301 addnode = 0;
1302
1303 do {
1304 if (node == NULL) break;
1305 if (xmlIsBlankNode(node)) continue;
1306
1307 if (xmlStrcmp (node->name, XMLSTR("host")) == 0) {
1308 server->host = (char *)xmlNodeListGetString(doc,
1309 node->xmlChildrenNode, 1);
1310 addnode = 1;
1311 } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) {
1312 tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1313 server->touch_interval = atoi(tmp);
1314 if (tmp) xmlFree(tmp);
1315 }
1316 server->next = NULL;
1317 } while ((node = node->next));
1318
1319 if (addnode) {
1320 dirnode = configuration->dir_list;
1321 if (dirnode == NULL) {
1322 configuration->dir_list = server;
1323 } else {
1324 while (dirnode->next) dirnode = dirnode->next;
1325
1326 dirnode->next = server;
1327 }
1328
1329 server = NULL;
1330 addnode = 0;
1331 }
1332 else {
1333 free (server);
1334 }
1335 }
1336
merge_mounts(mount_proxy * dst,mount_proxy * src)1337 static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
1338 ice_config_http_header_t *http_header_next;
1339 ice_config_http_header_t **http_header_tail;
1340
1341 if (!dst || !src)
1342 return;
1343
1344 if (!dst->username)
1345 dst->username = (char*)xmlStrdup((xmlChar*)src->username);
1346 if (!dst->password)
1347 dst->password = (char*)xmlStrdup((xmlChar*)src->password);
1348 if (!dst->dumpfile)
1349 dst->dumpfile = (char*)xmlStrdup((xmlChar*)src->dumpfile);
1350 if (!dst->intro_filename)
1351 dst->intro_filename = (char*)xmlStrdup((xmlChar*)src->intro_filename);
1352 if (!dst->fallback_when_full)
1353 dst->fallback_when_full = src->fallback_when_full;
1354 if (dst->max_listeners == -1)
1355 dst->max_listeners = src->max_listeners;
1356 if (!dst->fallback_mount)
1357 dst->fallback_mount = (char*)xmlStrdup((xmlChar*)src->fallback_mount);
1358 if (!dst->fallback_override)
1359 dst->fallback_override = src->fallback_override;
1360 if (!dst->no_mount)
1361 dst->no_mount = src->no_mount;
1362 if (dst->burst_size == -1)
1363 dst->burst_size = src->burst_size;
1364 if (!dst->queue_size_limit)
1365 dst->queue_size_limit = src->queue_size_limit;
1366 if (!dst->hidden)
1367 dst->hidden = src->hidden;
1368 if (!dst->source_timeout)
1369 dst->source_timeout = src->source_timeout;
1370 if (!dst->charset)
1371 dst->charset = (char*)xmlStrdup((xmlChar*)src->charset);
1372 if (dst->mp3_meta_interval == -1)
1373 dst->mp3_meta_interval = src->mp3_meta_interval;
1374 if (!dst->auth_type)
1375 dst->auth_type = (char*)xmlStrdup((xmlChar*)src->auth_type);
1376 // TODO: dst->auth
1377 if (!dst->cluster_password)
1378 dst->cluster_password = (char*)xmlStrdup((xmlChar*)src->cluster_password);
1379 // TODO: dst->auth_options
1380 if (!dst->on_connect)
1381 dst->on_connect = (char*)xmlStrdup((xmlChar*)src->on_connect);
1382 if (!dst->on_disconnect)
1383 dst->on_disconnect = (char*)xmlStrdup((xmlChar*)src->on_disconnect);
1384 if (!dst->max_listener_duration)
1385 dst->max_listener_duration = src->max_listener_duration;
1386 if (!dst->stream_name)
1387 dst->stream_name = (char*)xmlStrdup((xmlChar*)src->stream_name);
1388 if (!dst->stream_description)
1389 dst->stream_description = (char*)xmlStrdup((xmlChar*)src->stream_description);
1390 if (!dst->stream_url)
1391 dst->stream_url = (char*)xmlStrdup((xmlChar*)src->stream_url);
1392 if (!dst->stream_genre)
1393 dst->stream_genre = (char*)xmlStrdup((xmlChar*)src->stream_genre);
1394 if (!dst->bitrate)
1395 dst->bitrate = (char*)xmlStrdup((xmlChar*)src->bitrate);
1396 if (!dst->type)
1397 dst->type = (char*)xmlStrdup((xmlChar*)src->type);
1398 if (!dst->subtype)
1399 dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype);
1400 if (dst->yp_public == -1)
1401 dst->yp_public = src->yp_public;
1402
1403 if (dst->http_headers) {
1404 http_header_next = dst->http_headers;
1405 while (http_header_next->next) http_header_next = http_header_next->next;
1406 http_header_tail = &(http_header_next->next);
1407 } else {
1408 http_header_tail = &(dst->http_headers);
1409 }
1410 *http_header_tail = config_copy_http_header(src->http_headers);
1411 }
1412
_merge_mounts_all(ice_config_t * c)1413 static inline void _merge_mounts_all(ice_config_t *c) {
1414 mount_proxy *mountinfo = c->mounts;
1415 mount_proxy *default_mount;
1416
1417 for (; mountinfo; mountinfo = mountinfo->next)
1418 {
1419 if (mountinfo->mounttype != MOUNT_TYPE_NORMAL)
1420 continue;
1421
1422 default_mount = config_find_mount(c, mountinfo->mountname, MOUNT_TYPE_DEFAULT);
1423
1424 merge_mounts(mountinfo, default_mount);
1425 }
1426 }
1427
1428 /* return the mount details that match the supplied mountpoint */
config_find_mount(ice_config_t * config,const char * mount,mount_type type)1429 mount_proxy *config_find_mount (ice_config_t *config, const char *mount, mount_type type)
1430 {
1431 mount_proxy *mountinfo = config->mounts;
1432
1433 for (; mountinfo; mountinfo = mountinfo->next)
1434 {
1435 if (mountinfo->mounttype != type)
1436 continue;
1437
1438 if (mount == NULL || mountinfo->mountname == NULL)
1439 break;
1440
1441 if (mountinfo->mounttype == MOUNT_TYPE_NORMAL && strcmp (mountinfo->mountname, mount) == 0)
1442 break;
1443
1444 #ifndef _WIN32
1445 if (fnmatch(mountinfo->mountname, mount, FNM_PATHNAME) == 0)
1446 break;
1447 #else
1448 if (strcmp(mountinfo->mountname, mount) == 0)
1449 break;
1450 #endif
1451 }
1452
1453 /* retry with default mount */
1454 if (!mountinfo && type == MOUNT_TYPE_NORMAL)
1455 mountinfo = config_find_mount(config, mount, MOUNT_TYPE_DEFAULT);
1456
1457 return mountinfo;
1458 }
1459
1460 /* Helper function to locate the configuration details of the listening
1461 * socket
1462 */
config_get_listen_sock(ice_config_t * config,connection_t * con)1463 listener_t *config_get_listen_sock (ice_config_t *config, connection_t *con)
1464 {
1465 listener_t *listener;
1466 int i = 0;
1467
1468 listener = config->listen_sock;
1469 while (listener)
1470 {
1471 if (i >= global.server_sockets)
1472 listener = NULL;
1473 else
1474 {
1475 if (global.serversock[i] == con->serversock)
1476 break;
1477 listener = listener->next;
1478 i++;
1479 }
1480 }
1481 return listener;
1482 }
1483
1484