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)