From b3d184e8699eac8a683764c5a02dc3e39b1ce43f Mon Sep 17 00:00:00 2001 From: greenbender Date: Thu, 25 Feb 2016 13:43:32 +1100 Subject: [PATCH 01/12] Added ability to have multiple master servers We can basically aggregate all streams from any number of master servers --- src/cfgfile.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ src/cfgfile.h | 1 + src/slave.c | 76 ++++++++++++++++++++++++++++++++------------------- src/slave.h | 11 ++++++++ 4 files changed, 133 insertions(+), 28 deletions(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index f8fde5dec..800acd761 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -133,6 +133,7 @@ static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers); +static void _parse_master(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); @@ -487,6 +488,7 @@ void config_clear(ice_config_t *c) { ice_config_dir_t *dirnode, *nextdirnode; + master_server *master; relay_server *relay, *nextrelay; mount_proxy *mount, @@ -529,6 +531,11 @@ void config_clear(ice_config_t *c) while ((c->listen_sock = config_clear_listener(c->listen_sock))); + master = c->master; + while (master) { + master = master_free(master); + } + thread_mutex_lock(&(_locks.relay_lock)); relay = c->relay; while (relay) { @@ -934,6 +941,8 @@ static void _parse_root(xmlDocPtr doc, _parse_limits(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) { _parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers)); + } else if (xmlStrcmp(node->name, XMLSTR("master")) == 0) { + _parse_master(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp(node->name, XMLSTR("relay")) == 0) { _parse_relay(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) { @@ -1579,6 +1588,70 @@ static void _parse_http_headers(xmlDocPtr doc, xmlFree(value); } +static void _parse_master(xmlDocPtr doc, + xmlNodePtr node, + ice_config_t *configuration) +{ + char *tmp; + master_server *master = calloc(1, sizeof(master_server)); + master_server *current = configuration->master; + master_server *last = NULL; + + while(current) { + last = current; + current = current->next; + } + + if (last) { + last->next = master; + } else { + configuration->master = master; + } + + master->next = NULL; + master->on_demand = configuration->on_demand; + master->server = (char *) xmlCharStrdup("127.0.0.1"); + master->username = (char *) xmlCharStrdup(configuration->master_username); + master->password = (char *) xmlCharStrdup(configuration->master_password); + + do { + if (node == NULL) + break; + if (xmlIsBlankNode(node)) + continue; + + if (xmlStrcmp(node->name, XMLSTR("server")) == 0) { + if (master->server) + xmlFree(master->server); + master->server = (char *)xmlNodeListGetString(doc, + node->xmlChildrenNode, 1); + } else if (xmlStrcmp(node->name, XMLSTR("port")) == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (tmp) { + master->port = atoi(tmp); + xmlFree(tmp); + } else { + ICECAST_LOG_WARN(" setting must not be empty."); + } + } else if (xmlStrcmp(node->name, XMLSTR("username")) == 0) { + if (master->username) + xmlFree(master->username); + master->username = (char *)xmlNodeListGetString(doc, + node->xmlChildrenNode, 1); + } else if (xmlStrcmp(node->name, XMLSTR("password")) == 0) { + if (master->password) + xmlFree(master->password); + master->password = (char *)xmlNodeListGetString(doc, + node->xmlChildrenNode, 1); + } else if (xmlStrcmp(node->name, XMLSTR("on-demand")) == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + master->on_demand = util_str_to_bool(tmp); + if (tmp) + xmlFree(tmp); + } + } while ((node = node->next)); +} + static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) diff --git a/src/cfgfile.h b/src/cfgfile.h index d18725c6d..0b0938c0b 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -218,6 +218,7 @@ typedef struct ice_config_tag { /* is TLS supported by the server? */ int tls_ok; + master_server *master; relay_server *relay; mount_proxy *mounts; diff --git a/src/slave.c b/src/slave.c index 59c1b271c..16aebc4cf 100644 --- a/src/slave.c +++ b/src/slave.c @@ -63,6 +63,19 @@ static volatile int update_all_mounts = 0; static volatile unsigned int max_interval = 0; static mutex_t _slave_mutex; // protects update_settings, update_all_mounts, max_interval +master_server *master_free (master_server *master) +{ + master_server *next = master->next; + ICECAST_LOG_DEBUG("freeing master %s:%d", master->server, master->port); + xmlFree (master->server); + if (master->username) + xmlFree (master->username); + if (master->password) + xmlFree (master->password); + free (master); + return next; +} + relay_server *relay_free (relay_server *relay) { relay_server *next = relay->next; @@ -598,10 +611,8 @@ static void relay_check_streams (relay_server *to_start, } -static int update_from_master(ice_config_t *config) +static int update_from_master(master_server *master) { - char *master = NULL, *password = NULL, *username= NULL; - int port; sock_t mastersock; int ret = 0; char buf[256]; @@ -610,23 +621,12 @@ static int update_from_master(ice_config_t *config) char *authheader, *data; relay_server *new_relays = NULL, *cleanup_relays; int len, count = 1; - int on_demand; - - username = strdup(config->master_username); - if (config->master_password) - password = strdup(config->master_password); - - if (config->master_server) - master = strdup(config->master_server); - port = config->master_server_port; - - if (password == NULL || master == NULL || port == 0) + if (master->password == NULL || master->server == NULL || master->port == 0) break; - on_demand = config->on_demand; ret = 1; config_release_config(); - mastersock = sock_connect_wto(master, port, 10); + mastersock = sock_connect_wto(master->server, master->port, 10); if (mastersock == SOCK_ERROR) { @@ -634,9 +634,9 @@ static int update_from_master(ice_config_t *config) break; } - len = strlen(username) + strlen(password) + 2; + len = strlen(master->username) + strlen(master->password) + 2; authheader = malloc(len); - snprintf (authheader, len, "%s:%s", username, password); + snprintf (authheader, len, "%s:%s", master->username, master->password); data = util_base64_encode(authheader, len); sock_write (mastersock, "GET /admin/streamlist.txt HTTP/1.0\r\n" @@ -682,14 +682,14 @@ static int update_from_master(ice_config_t *config) } else { - r->server = (char *)xmlCharStrdup (master); - r->port = port; + r->server = (char *)xmlCharStrdup (master->server); + r->port = master->port; } r->mount = strdup(parsed_uri->path); r->localmount = strdup(parsed_uri->path); r->mp3metadata = 1; - r->on_demand = on_demand; + r->on_demand = master->on_demand; r->next = new_relays; ICECAST_LOG_DEBUG("Added relay host=\"%s\", port=%d, mount=\"%s\"", r->server, r->port, r->mount); new_relays = r; @@ -708,12 +708,24 @@ static int update_from_master(ice_config_t *config) } while(0); - if (master) - free (master); - if (username) - free (username); - if (password) - free (password); + return ret; +} + +static int update_from_master_legacy(ice_config_t *config) +{ + master_server *master = calloc (1, sizeof (master_server)); + int ret = 0; + + if (master) { + master->username = strdup(config->master_username); + if (config->master_password) + master->password = strdup(config->master_password); + if (config->master_server) + master->server = strdup(config->master_server); + master->port = config->master_server_port; + ret = update_from_master(master); + master_free(master); + } return ret; } @@ -759,6 +771,7 @@ static void *_slave_thread(void *arg) thread_mutex_lock(&_slave_mutex); if (max_interval <= interval) { + master_server *master; ICECAST_LOG_DEBUG("checking master stream list"); config = config_get_config(); @@ -767,9 +780,16 @@ static void *_slave_thread(void *arg) interval = 0; max_interval = config->master_update_interval; thread_mutex_unlock(&_slave_mutex); + + /* update all non-legacy master servers */ + master = config->master; + while (master) { + update_from_master(master); + master = master->next; + } /* the connection could take some time, so the lock can drop */ - if (update_from_master (config)) + if (update_from_master_legacy (config)) config = config_get_config(); thread_mutex_lock (&(config_locks()->relay_lock)); diff --git a/src/slave.h b/src/slave.h index d8ff50de0..9d631bd40 100644 --- a/src/slave.h +++ b/src/slave.h @@ -15,6 +15,15 @@ #include "common/thread/thread.h" +typedef struct _master_server { + char *server; + int port; + char *username; + char *password; + int on_demand; + struct _master_server *next; +} master_server; + typedef struct _relay_server { char *server; int port; @@ -34,6 +43,8 @@ typedef struct _relay_server { } relay_server; +master_server *master_free (master_server *master); + void slave_initialize(void); void slave_shutdown(void); void slave_update_all_mounts (void); From 48403310fa1a09abc084a5da938bfcdc8810cfb3 Mon Sep 17 00:00:00 2001 From: greenbender Date: Thu, 25 Feb 2016 14:04:09 +1100 Subject: [PATCH 02/12] master_password can be NULL --- src/cfgfile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index 800acd761..2c68fe583 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -1612,7 +1612,8 @@ static void _parse_master(xmlDocPtr doc, master->on_demand = configuration->on_demand; master->server = (char *) xmlCharStrdup("127.0.0.1"); master->username = (char *) xmlCharStrdup(configuration->master_username); - master->password = (char *) xmlCharStrdup(configuration->master_password); + if (configuration->master_password) + master->password = (char *) xmlCharStrdup(configuration->master_password); do { if (node == NULL) From 324f89d2bccf0e04f22844c133129b39515a515f Mon Sep 17 00:00:00 2001 From: greenbender Date: Thu, 25 Feb 2016 14:14:23 +1100 Subject: [PATCH 03/12] Aggregation master server example Added an example of a master relay server aggregation --- conf/icecast.xml.in | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/conf/icecast.xml.in b/conf/icecast.xml.in index 4fa43da15..bff22da14 100644 --- a/conf/icecast.xml.in +++ b/conf/icecast.xml.in @@ -108,6 +108,20 @@ + + + + From e0f867c6a7bd7ef4056d1125097ae3f5f26ec6fe Mon Sep 17 00:00:00 2001 From: greenbender Date: Thu, 25 Feb 2016 15:24:16 +1100 Subject: [PATCH 04/12] Added on_demand to legacy master relay --- src/slave.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slave.c b/src/slave.c index 16aebc4cf..5fb8acdab 100644 --- a/src/slave.c +++ b/src/slave.c @@ -723,6 +723,7 @@ static int update_from_master_legacy(ice_config_t *config) if (config->master_server) master->server = strdup(config->master_server); master->port = config->master_server_port; + master->on_demand = config->on_demand; ret = update_from_master(master); master_free(master); } From a36d4b1bfb5ba61dc4bdb0c11a9d8f35888bcf2b Mon Sep 17 00:00:00 2001 From: greenbender Date: Thu, 25 Feb 2016 15:40:03 +1100 Subject: [PATCH 05/12] Removed lock/unlock on config for master updates At this point is it more for ease than anything else. The locks could be released quickly with some effort. --- src/slave.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slave.c b/src/slave.c index 5fb8acdab..3c5f2608b 100644 --- a/src/slave.c +++ b/src/slave.c @@ -625,7 +625,6 @@ static int update_from_master(master_server *master) if (master->password == NULL || master->server == NULL || master->port == 0) break; ret = 1; - config_release_config(); mastersock = sock_connect_wto(master->server, master->port, 10); if (mastersock == SOCK_ERROR) @@ -782,16 +781,17 @@ static void *_slave_thread(void *arg) max_interval = config->master_update_interval; thread_mutex_unlock(&_slave_mutex); - /* update all non-legacy master servers */ + /* update all non-legacy master servers. the config lock is being + * held for the entire update process. consider making a copy of + * the master linked list and releasing the lock */ master = config->master; while (master) { update_from_master(master); master = master->next; } - /* the connection could take some time, so the lock can drop */ - if (update_from_master_legacy (config)) - config = config_get_config(); + /* update legacy master server */ + update_from_master_legacy (config); thread_mutex_lock (&(config_locks()->relay_lock)); From c06dcec83efd3164b2f94be8d12ea6b020050845 Mon Sep 17 00:00:00 2001 From: greenbender Date: Thu, 25 Feb 2016 16:42:51 +1100 Subject: [PATCH 06/12] Added namespace support for aggregating relays --- conf/icecast.xml.in | 1 + doc/relaying.html | 33 +++++++++++++++++++++++++++++++++ src/cfgfile.c | 5 +++++ src/slave.c | 11 ++++++++++- src/slave.h | 1 + 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/conf/icecast.xml.in b/conf/icecast.xml.in index bff22da14..99c27822f 100644 --- a/conf/icecast.xml.in +++ b/conf/icecast.xml.in @@ -118,6 +118,7 @@ 8001 relay hackme + master1 1 --> diff --git a/doc/relaying.html b/doc/relaying.html index 4c22d8a91..b9a71c515 100644 --- a/doc/relaying.html +++ b/doc/relaying.html @@ -35,6 +35,9 @@

Type of Relays

will also periodically check the master server to see if any new mountpoints have attached and if so will relay those as well.

+

This "master-slave" type relay has been extended to support aggregation so that multiple masters can be given +and the slave will "aggregate" all of the mountpoints for those master servers.

+

The second type of relay is a “single-broadcast” relay. In this case, the slave server is configured with a server IP, port and mount and only the mountpoint specified is relayed. In order to relay a broadcast stream on a Shoutcast server, you must use the “single-broadcast” relay and specify a mountpoint of /.

@@ -61,6 +64,36 @@

Setting Up a Master-Slave Relay

+
+

Setting Up a Master-Slave Aggregating Relay

+

In order to setup a relay of this type all servers (the one you wish to relay and the one doing the relaying) +need to be Icecast 2 servers. The following configuration snippet is used as an example:

+ +
<master-update-interval>120</master-update-interval>
+<master>
+    <server>192.168.1.11</server>
+    <port>8001</port>
+    <namespace>/upstream1</namespace>
+    <password>hackme</password>
+    <on-demand>1</on-demand>
+</master>
+<master>
+    <server>192.168.1.12</server>
+    <port>8001</port>
+    <password>hackme</password>
+</master>
+
+ +

In this example, this configuration is setup in the server which will be doing the relaying (slave server). +The master servers in this case need not be configured (and actually they are unaware of the relaying being performed) +as relays. When the slave server is started, it will connect to each of the master servers located at 192.168.1.11:8001 +and 192.168.1.12:8001 and will begin to relay all mountpoints connected to the master servers. Additionally, +every master-update-interval (120 seconds in this case) the slave server will poll the master servers to see if any new +mountpoints have connected, and if so, the slave server will relay those as well. Note that all mountpoints of the master +server at 192.168.1.11:8001 will have the namespace "/upstream1" prepended to it's mountpoints.

+ +
+

Setting Up a Single-Broadcast Relay

In this case, the master server need not be an Icecast 2 server. Supported master servers for a single-broadcast diff --git a/src/cfgfile.c b/src/cfgfile.c index 2c68fe583..b68a84e85 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -1644,6 +1644,11 @@ static void _parse_master(xmlDocPtr doc, xmlFree(master->password); master->password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + } else if (xmlStrcmp(node->name, XMLSTR("namespace")) == 0) { + if (master->namespace) + xmlFree(master->namespace); + master->namespace = (char *)xmlNodeListGetString(doc, + node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("on-demand")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); master->on_demand = util_str_to_bool(tmp); diff --git a/src/slave.c b/src/slave.c index 3c5f2608b..c22540d19 100644 --- a/src/slave.c +++ b/src/slave.c @@ -72,6 +72,8 @@ master_server *master_free (master_server *master) xmlFree (master->username); if (master->password) xmlFree (master->password); + if (master->namespace) + xmlFree(master->namespace); free (master); return next; } @@ -686,7 +688,14 @@ static int update_from_master(master_server *master) } r->mount = strdup(parsed_uri->path); - r->localmount = strdup(parsed_uri->path); + if (master->namespace) + { + int mountlen = strlen(master->namespace) + strlen(parsed_uri->path) + 1; + r->localmount = malloc(mountlen); + snprintf(r->localmount, mountlen, "%s%s", master->namespace, parsed_uri->path); + } else { + r->localmount = strdup(parsed_uri->path); + } r->mp3metadata = 1; r->on_demand = master->on_demand; r->next = new_relays; diff --git a/src/slave.h b/src/slave.h index 9d631bd40..aa478a25a 100644 --- a/src/slave.h +++ b/src/slave.h @@ -21,6 +21,7 @@ typedef struct _master_server { char *username; char *password; int on_demand; + char *namespace; struct _master_server *next; } master_server; From 7a2ff037d4ba7499955bb2e40728df71217b700e Mon Sep 17 00:00:00 2001 From: greenbender Date: Fri, 26 Feb 2016 14:07:36 +1100 Subject: [PATCH 07/12] Copy out master list from config Config locking during update_from_master is now avoided. This method is still inefficient as the copy is performed each master-update-interval when it could be done only when the config changes --- src/slave.c | 146 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 37 deletions(-) diff --git a/src/slave.c b/src/slave.c index c22540d19..6d55139cc 100644 --- a/src/slave.c +++ b/src/slave.c @@ -63,21 +63,99 @@ static volatile int update_all_mounts = 0; static volatile unsigned int max_interval = 0; static mutex_t _slave_mutex; // protects update_settings, update_all_mounts, max_interval -master_server *master_free (master_server *master) + +/* free a master and return its next master */ +master_server *master_free(master_server *master) { master_server *next = master->next; ICECAST_LOG_DEBUG("freeing master %s:%d", master->server, master->port); - xmlFree (master->server); + xmlFree(master->server); if (master->username) - xmlFree (master->username); + xmlFree(master->username); if (master->password) - xmlFree (master->password); + xmlFree(master->password); if (master->namespace) xmlFree(master->namespace); - free (master); + free(master); return next; } + +/* copy a master and return the copy */ +static master_server *master_copy(master_server *master) +{ + master_server *copy = calloc(1, sizeof(*master)); + + if (copy) + { + copy->server = (char *)xmlCharStrdup(master->server); + if (master->username) + copy->username = (char *)xmlCharStrdup(master->username); + if (master->password) + copy->password = (char *)xmlCharStrdup(master->password); + if (master->namespace) + copy->namespace = (char *)xmlCharStrdup(master->namespace); + copy->port = master->port; + copy->on_demand = master->on_demand; + } + return copy; +} + + +/* free master list and return NULL */ +static master_server *master_list_free(master_server *list) +{ + while ((list = master_free(list))); + return list; +} + + +/* insert a master into a master list and return the list head */ +static master_server *master_list_insert(master_server *list, master_server *master) +{ + master->next = list; + return master; +} + + +/* copy a master list and return copied list */ +static master_server *master_list_copy(master_server *list) { + master_server *list_copy = NULL; + + while (list) + { + master_server *copy = master_copy(list); + if (copy == NULL) + { + list_copy = master_list_free(list_copy); + break; + } + list_copy = master_list_insert(list_copy, copy); + list = list->next; + } + + return list_copy; +} + + +/* turn a legacy master (from config) into a master and return it */ +static master_server *master_from_legacy(ice_config_t *config) { + master_server *master = calloc(1, sizeof(*master)); + + if (master) { + master->username = strdup(config->master_username); + if (config->master_password) + master->password = strdup(config->master_password); + if (config->master_server) + master->server = strdup(config->master_server); + master->port = config->master_server_port; + master->on_demand = config->on_demand; + } + + return master; +} + + relay_server *relay_free (relay_server *relay) { relay_server *next = relay->next; @@ -719,27 +797,6 @@ static int update_from_master(master_server *master) return ret; } -static int update_from_master_legacy(ice_config_t *config) -{ - master_server *master = calloc (1, sizeof (master_server)); - int ret = 0; - - if (master) { - master->username = strdup(config->master_username); - if (config->master_password) - master->password = strdup(config->master_password); - if (config->master_server) - master->server = strdup(config->master_server); - master->port = config->master_server_port; - master->on_demand = config->on_demand; - ret = update_from_master(master); - master_free(master); - } - - return ret; -} - - static void *_slave_thread(void *arg) { ice_config_t *config; @@ -780,27 +837,42 @@ static void *_slave_thread(void *arg) thread_mutex_lock(&_slave_mutex); if (max_interval <= interval) { - master_server *master; + master_server *list = NULL; + ICECAST_LOG_DEBUG("checking master stream list"); - config = config_get_config(); if (max_interval == 0) skip_timer = 1; interval = 0; + + config = config_get_config(); max_interval = config->master_update_interval; + config_release_config(); + thread_mutex_unlock(&_slave_mutex); - /* update all non-legacy master servers. the config lock is being - * held for the entire update process. consider making a copy of - * the master linked list and releasing the lock */ - master = config->master; - while (master) { - update_from_master(master); - master = master->next; + /* copy master list and insert legacy master from config. note: + * keeping a global list of master servers that only changes on a + * config change would be much more efficient than performing a + * copy each time we do an update -- implement this (and the + * locking that goes with along with this approach) */ + config = config_get_config(); + list = master_list_insert( + master_list_copy(config->master), + master_from_legacy(config) + ); + config_release_config(); + + /* update all master servers */ + while (list) { + update_from_master(list); + list = list->next; } - /* update legacy master server */ - update_from_master_legacy (config); + if (list) + master_list_free(list); + + config = config_get_config(); thread_mutex_lock (&(config_locks()->relay_lock)); From e4a015587f426eba72bd61a10ca8520b56917240 Mon Sep 17 00:00:00 2001 From: greenbender Date: Fri, 26 Feb 2016 15:21:56 +1100 Subject: [PATCH 08/12] Added a bit of safety for list_free No need to check for NULL list param when calling --- src/slave.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/slave.c b/src/slave.c index 6d55139cc..b95d3c46d 100644 --- a/src/slave.c +++ b/src/slave.c @@ -67,16 +67,20 @@ static mutex_t _slave_mutex; // protects update_settings, update_all_mounts, max /* free a master and return its next master */ master_server *master_free(master_server *master) { - master_server *next = master->next; - ICECAST_LOG_DEBUG("freeing master %s:%d", master->server, master->port); - xmlFree(master->server); - if (master->username) - xmlFree(master->username); - if (master->password) - xmlFree(master->password); - if (master->namespace) - xmlFree(master->namespace); - free(master); + master_server *next = NULL; + if (master) + { + next = master->next; + ICECAST_LOG_DEBUG("freeing master %s:%d", master->server, master->port); + xmlFree(master->server); + if (master->username) + xmlFree(master->username); + if (master->password) + xmlFree(master->password); + if (master->namespace) + xmlFree(master->namespace); + free(master); + } return next; } @@ -869,8 +873,7 @@ static void *_slave_thread(void *arg) list = list->next; } - if (list) - master_list_free(list); + master_list_free(list); config = config_get_config(); From dfa29a379c447597dfb66f1f43adda6fb42b27ab Mon Sep 17 00:00:00 2001 From: greenbender Date: Sun, 12 Feb 2017 20:30:52 +1100 Subject: [PATCH 09/12] Made server optional for master Rather than default to 127.0.0.1 make a required field in and warn if it is not supplied. Any master that has a NULL server will be skipped during updates. Also ensure that server is non-NULL before freeing. --- src/cfgfile.c | 6 +++++- src/slave.c | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index b68a84e85..192abb2c4 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -1610,7 +1610,7 @@ static void _parse_master(xmlDocPtr doc, master->next = NULL; master->on_demand = configuration->on_demand; - master->server = (char *) xmlCharStrdup("127.0.0.1"); + master->server = NULL; master->username = (char *) xmlCharStrdup(configuration->master_username); if (configuration->master_password) master->password = (char *) xmlCharStrdup(configuration->master_password); @@ -1656,6 +1656,10 @@ static void _parse_master(xmlDocPtr doc, xmlFree(tmp); } } while ((node = node->next)); + + if (master->server == NULL) { + ICECAST_LOG_WARN(" is required for ."); + } } static void _parse_relay(xmlDocPtr doc, diff --git a/src/slave.c b/src/slave.c index b95d3c46d..dae09c394 100644 --- a/src/slave.c +++ b/src/slave.c @@ -72,7 +72,8 @@ master_server *master_free(master_server *master) { next = master->next; ICECAST_LOG_DEBUG("freeing master %s:%d", master->server, master->port); - xmlFree(master->server); + if (master->server) + xmlFree(master->server); if (master->username) xmlFree(master->username); if (master->password) From ca21b843b85c1804a21ab097099cab99d1688764 Mon Sep 17 00:00:00 2001 From: greenbender Date: Sun, 12 Feb 2017 21:02:01 +1100 Subject: [PATCH 10/12] Change master_list_free to return void This makes things a bit more explicit where the function is called --- src/slave.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slave.c b/src/slave.c index dae09c394..845f9e637 100644 --- a/src/slave.c +++ b/src/slave.c @@ -107,11 +107,10 @@ static master_server *master_copy(master_server *master) } -/* free master list and return NULL */ -static master_server *master_list_free(master_server *list) +/* free master list */ +static void master_list_free(master_server *list) { while ((list = master_free(list))); - return list; } @@ -132,7 +131,8 @@ static master_server *master_list_copy(master_server *list) { master_server *copy = master_copy(list); if (copy == NULL) { - list_copy = master_list_free(list_copy); + master_list_free(list_copy); + list_copy = NULL; break; } list_copy = master_list_insert(list_copy, copy); From 26ce215b8dea4ca92f43f20d9dba8fb3072e1fad Mon Sep 17 00:00:00 2001 From: greenbender Date: Sun, 12 Feb 2017 21:04:03 +1100 Subject: [PATCH 11/12] Ensure valid uri for localmount When a namespace is supplied for a master ensure that the URI for the localmount starts with a forward slash. When the namespace already starts with a forward slash use it as is, otherwise prepend a forward slash to the localmount. --- src/slave.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slave.c b/src/slave.c index 845f9e637..6b41c2276 100644 --- a/src/slave.c +++ b/src/slave.c @@ -773,9 +773,11 @@ static int update_from_master(master_server *master) r->mount = strdup(parsed_uri->path); if (master->namespace) { - int mountlen = strlen(master->namespace) + strlen(parsed_uri->path) + 1; + int mountlen = strlen(master->namespace) + strlen(parsed_uri->path) + 2; r->localmount = malloc(mountlen); - snprintf(r->localmount, mountlen, "%s%s", master->namespace, parsed_uri->path); + snprintf(r->localmount, mountlen, "%s%s%s", + (master->namespace[0] == '/') ? "" : "/", master->namespace, + parsed_uri->path); } else { r->localmount = strdup(parsed_uri->path); } From 97f473090d62d892774d31ac409ffa0f20045b03 Mon Sep 17 00:00:00 2001 From: greenbender Date: Sun, 12 Feb 2017 21:07:56 +1100 Subject: [PATCH 12/12] Be explicit with init NULL value of namespace Even though memory is calloc'ed for the master structure being explicit is probably a good idea. --- src/cfgfile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cfgfile.c b/src/cfgfile.c index 192abb2c4..bd9d0cbd8 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -1614,6 +1614,7 @@ static void _parse_master(xmlDocPtr doc, master->username = (char *) xmlCharStrdup(configuration->master_username); if (configuration->master_password) master->password = (char *) xmlCharStrdup(configuration->master_password); + master->namespace = NULL; do { if (node == NULL)