Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master-Slave Aggregating Relay (multiple master setup) #5

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
15 changes: 15 additions & 0 deletions conf/icecast.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@
<!--<master-update-interval>120</master-update-interval>-->
<!--<master-password>hackme</master-password>-->

<!-- Aggregation
useful for aggregating all the mounts of any number of master relays.
-->

<!--
<master>
<server>127.0.0.1</server>
<port>8001</port>
<username>relay</username>
<password>hackme</password>
<namespace>master1</namespace>
<on-demand>1</on-demand>
</master>
-->

<!-- Setting this makes all relays on-demand unless overridden, this is
useful for master relays which do not have <relay> definitions here.
The default is 0 -->
Expand Down
33 changes: 33 additions & 0 deletions doc/relaying.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ <h3 id="type-of-relays">Type of Relays</h3>
will also periodically check the master server to see if any new mountpoints have attached and if so will relay those
as well. </p>

<p>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. </p>

<p>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 <code>/</code>.</p>
Expand All @@ -61,6 +64,36 @@ <h3 id="setting-up-a-master-slave-relay">Setting Up a Master-Slave Relay</h3>

</div>

<div class="article">
<h3 id="setting-up-a-master-slave-aggregating-relay">Setting Up a Master-Slave Aggregating Relay</h3>
<p>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:</p>

<div class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;master-update-interval&gt;</span>120<span class="nt">&lt;/master-update-interval&gt;</span>
<span class="nt">&lt;master&gt;</span>
<span class="nt">&lt;server&gt;</span>192.168.1.11<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;port&gt;</span>8001<span class="nt">&lt;/port&gt;</span>
<span class="nt">&lt;namespace&gt;</span>/upstream1<span class="nt">&lt;/namespace&gt;</span>
<span class="nt">&lt;password&gt;</span>hackme<span class="nt">&lt;/password&gt;</span>
<span class="nt">&lt;on-demand&gt;</span>1<span class="nt">&lt;/on-demand&gt;</span>
<span class="nt">&lt;/master&gt;</span>
<span class="nt">&lt;master&gt;</span>
<span class="nt">&lt;server&gt;</span>192.168.1.12<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;port&gt;</span>8001<span class="nt">&lt;/port&gt;</span>
<span class="nt">&lt;password&gt;</span>hackme<span class="nt">&lt;/password&gt;</span>
<span class="nt">&lt;/master&gt;</span>
</code></pre></div>

<p>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. </p>

</div>

<div class="article">
<h3 id="setting-up-a-single-broadcast-relay">Setting Up a Single-Broadcast Relay</h3>
<p>In this case, the master server need not be an Icecast 2 server. Supported master servers for a single-broadcast
Expand Down
84 changes: 84 additions & 0 deletions src/cfgfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -1579,6 +1588,81 @@ 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 = NULL;
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)
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("<port> 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("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);
if (tmp)
xmlFree(tmp);
}
} while ((node = node->next));

if (master->server == NULL) {
ICECAST_LOG_WARN("<server> is required for <master>.");
}
}

static void _parse_relay(xmlDocPtr doc,
xmlNodePtr node,
ice_config_t *configuration)
Expand Down
1 change: 1 addition & 0 deletions src/cfgfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading