1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-11-03 04:17:17 -05:00

bump version. mainly an update of 302 work, other bits missed out from before

svn path=/icecast/branches/kh/icecast/; revision=10828
This commit is contained in:
Karl Heyes 2006-02-17 00:42:03 +00:00
parent a44c99bd07
commit a9516a9e31
20 changed files with 283 additions and 217 deletions

28
NEWS
View File

@ -9,8 +9,32 @@ Feature differences from SVN trunk
TODO
. update slave host handling to add entry via url, as on-demand relays don't
connect until there are listeners.
. get feedback from people on listener auth via url, Stephen Nixon has done
some auth scripts that people can use at http://imux.net/icecast/
2.3-kh3
. add source auth via authenticator, affects certain admin access as well.
Only url auth using it currently
. relays now have start timestamps, prevents a possible constant rescanning
effect with multiple relay failure case
. fix memory leak in ogg flac case.
. update YP, get bitrate from stats (incoming_bitrate), if not provided. Issue
yp add after 60 secs, gives time for bitrates to settle.
. cleanups in auth setup, push more setup code into the core auth handler.
. when moving listeners, if most recent refbuf is not a sync point then use
burst point. Fallback theora streams can be affected by this.
. drop master-redirect-port, use <port>.
. set <master-redirect> (in slave) non-zero to send IP/port details in
streamlist request, so that new listener redirection from master is possible.
. set <max-redirect-slaves> (in master) to specify the number of slave servers
that can request listener redirection, default 0.
. prevent avg/total byte stats for fallback to file sources.
. allow for server id to be defined in xml.
. add connected stat to source, duration in seconds.
. increase average stats for bitrate calculation to 30 seconds
. increase sleep duration in connection thread to 100ms
. make source clients report read bytes in access.log
. bypass clients limit check for ssl connections, let admin do stuff
. various type cleanups, gcc4 show various signed/unsigned issues.
. sync up with trunk, win32, os.h/compat.h, minor type definitions
2.3-kh2
. merges from post 2.3 release/feedback

View File

@ -74,7 +74,7 @@
<a href="/auth.xsl"><img border="0" src="/images/key.png"/></a> Authentication Required
</xsl:when>
<xsl:otherwise>
<a href="{@mount}.m3u"><img border="0" src="/tunein.png"/></a>
<a href="{@mount}.m3u"><img border="0" src="/images/tunein.png"/></a>
</xsl:otherwise>
</xsl:choose>
Mount Point : (<xsl:value-of select="@mount" />)

View File

@ -2,7 +2,6 @@
<limits>
<clients>100</clients>
<sources>2</sources>
<threadpool>5</threadpool>
<queue-size>524288</queue-size>
<client-timeout>30</client-timeout>
<header-timeout>15</header-timeout>
@ -29,10 +28,6 @@
<directory>
<yp-url-timeout>15</yp-url-timeout>
<yp-url>http://dir.xiph.org/cgi-bin/yp-cgi</yp-url>
</directory>
<directory>
<yp-url-timeout>15</yp-url-timeout>
<yp-url>http://www.oddsock.org/cgi-bin/yp-cgi</yp-url>
</directory>
-->
@ -69,9 +64,9 @@
<!--<relays-on-demand>1</relays-on-demand>-->
<!-- Report <hostname> and this port to master server for redirecting
clients to this slave -->
<!--<master-redirect-port>8000</master-redirect-port>-->
<!-- Request the master server to redirect new listeners to this slave
the details passed are based on <hostname> and <port> -->
<!--<master-redirect>1</master-redirect>-->
<!-- Relays. State connection information, and by default
request inline metadata for mp3 streams if available.

View File

@ -1,4 +1,4 @@
AC_INIT([Icecast], [2.3-kh2], [karl@xiph.org])
AC_INIT([Icecast], [2.3-kh3], [karl@xiph.org])
AC_PREREQ(2.54)
AC_CONFIG_SRCDIR(src/main.c)

View File

@ -85,6 +85,7 @@ config file. The following shows the list of options available :</p>
&lt;mount&gt;
&lt;mount-name&gt;/example.ogg&lt;/mount-name&gt;
&lt;authentication type="url"&gt;
&lt;option name="stream_auth" value="http://myauthserver.com/stream_auth.php"/&gt;
&lt;option name="mount_add" value="http://myauthserver.com/stream_start.php"/&gt;
&lt;option name="mount_remove" value="http://myauthserver.com/stream_end.php"/&gt;
&lt;option name="listener_add" value="http://myauthserver.com/listener_joined.php"/&gt;
@ -98,6 +99,13 @@ config file. The following shows the list of options available :</p>
</pre>
<p>The options are described below in more detail, each of which is optional, but in each
case, within the POST data, the value for each setting is encoded.</p>
<h3>stream_auth</h3>
<p>This URL is for determining whether a source or admin request is allowed to proceed. This
is only used for source client connections and admin requests which apply to sources.</p>
<p>POST details are </p>
<pre>
action=stream_auth&amp;mount=&amp;ip=&amp;server=&amp;port=&amp;user=&amp;pass=%s
</pre>
<h3>mount_add</h3>
<p>This URL is for informing the auth server of a stream starting. No listener information
is passed for this, but can be used to initialise any details the auth server may have.

View File

@ -22,14 +22,37 @@
<br />
<br />
<h2>Setting Up A Master-Slave Relay</h2>
<p>In order to setup a relay of this type both servers (the one you wish to relay and the one doing the relaying) need to be icecast2 servers. The following configuration snippet is used as an example:</p>
<p>In order to setup a relay of this type both servers (the one you wish to relay and the one
doing the relaying) need to be icecast2 servers. The following configuration snippet is used
as an example:</p>
<pre>
&lt;master-server&gt;192.168.1.11&lt;/master-server&gt;
&lt;master-server-port&gt;8001&lt;/master-server-port&gt;
&lt;master-update-interval&gt;120&lt;/master-update-interval&gt;
&lt;master-username&gt;relay&lt;/master-username&gt;
&lt;master-password&gt;hackme&lt;/master-password&gt;
</pre>
In this example, this configuration is setup in the server which will be doing the relaying (slave server). The master server in this case need not be configured (and actually is unaware of the relaying being performed) as a relay. When the slave server is started, it will connect to the master server located at 192.168.1.11:8001 and will begin to relay all mountpoints connected to the master server. Additionally, every master-update-interval (120 seconds in this case) the slave server will poll the master server to see if any new mountpoints have connected, and if so, the slave server will relay those as well. Note that the names of the mountpoints on the slave server will be identical to those on the master server.
<p>In this example, this configuration is setup in the server which will be doing the relaying
(slave server). The master server in this case need not be configured (and actually is unaware
of the relaying being performed) as a relay. When the slave server is started, it will connect
to the master server located at 192.168.1.11:8001 and will begin to relay all non-hidden
mountpoints connected to the master server. Additionally, every master-update-interval (120
seconds in this case) the slave server will poll the master server to see if any new mountpoints
have connected, and if so, the slave server will relay those as well. Note that the names of
the mountpoints on the slave server will be identical to those on the master server.</p>
<p>To extend on the idea of load sharing, it is possible for a slave icecast2 to communicate
certain information to allow for new listeners to be redirected from the master server to the
slave. In such cases, the master will send to the listener a HTTP 302 response code with a URL
of the slave server which has been randomly selected.</p>
</p>To enable this certain settings have to be enabled. In the master</p>
<pre>
&lt;max-redirect-slaves&gt;5&lt;/max-redirect-slaves&gt;
</pre>
<p>This limits the redirection mechanism to 5 slaves, the default is 0, preventing any attempts
to redirect new listeners. In the slave </p>
<pre>
&lt;master-redirect&gt;1&lt;/master-redirect&gt;
</pre>
<br />
<br />
<br />

View File

@ -1160,6 +1160,9 @@ static void command_list_mounts(client_t *client, int response)
ice_config_t *config = config_get_config ();
mount_proxy *mountinfo = config->mounts;
/* do any redirector updates */
redirector_update (client);
buf = client->refbuf->data;
ret = snprintf (buf, remaining,
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");

View File

@ -410,7 +410,7 @@ static int add_authenticated_listener (const char *mount, mount_proxy *mountinfo
DEBUG0 ("client authenticated, passed to source");
else
{
if (slave_redirect (mount, client))
if (redirect_client (mount, client))
ret = 0;
}
}
@ -472,7 +472,7 @@ void add_client (const char *mount, client_t *client)
if (connection_check_relay_pass(client->parser))
{
client_as_slave (client);
client->is_slave = 1;
INFO0 ("client connected as slave");
}
config = config_get_config();

View File

@ -408,7 +408,7 @@ static void url_stream_auth (auth_client *auth_user)
{
client_t *client = auth_user->client;
auth_url *url = client->auth->state;
char *mount, *host, *user, *pass, *ipaddr, *metadata="";
char *mount, *host, *user, *pass, *ipaddr, *admin="";
char post [4096];
if (strchr (url->stream_auth, '@') == NULL)
@ -426,7 +426,7 @@ static void url_stream_auth (auth_client *auth_user)
if (strncmp (auth_user->mount, "/admin/", 7) == 0)
{
mount = util_url_escape (httpp_get_query_param (client->parser, "mount"));
metadata = "&metadata=1";
admin = "&admin=1";
}
else
mount = util_url_escape (auth_user->mount);
@ -436,8 +436,8 @@ static void url_stream_auth (auth_client *auth_user)
ipaddr = util_url_escape (client->con->ip);
snprintf (post, sizeof (post),
"action=stream_auth&mount=%sip=%s&server=%s&port=%d&user=%s&pass=%s%s",
mount, ipaddr, host, auth_user->port, user, pass, metadata);
"action=stream_auth&mount=%s&ip=%s&server=%s&port=%d&user=%s&pass=%s%s",
mount, ipaddr, host, auth_user->port, user, pass, admin);
free (ipaddr);
free (user);
free (pass);

View File

@ -367,7 +367,6 @@ static void _set_defaults(ice_config_t *configuration)
configuration->master_username = (char*)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
configuration->master_password = NULL;
configuration->master_relay_auth = 0;
configuration->master_redirect_port = 0;
configuration->base_dir = CONFIG_DEFAULT_BASE_DIR;
configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR;
@ -458,10 +457,6 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_server_port = atoi(tmp);
xmlFree (tmp);
} else if (xmlStrcmp(node->name, XMLSTR ("master-redirect-port")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_redirect_port = atoi(tmp);
xmlFree (tmp);
} else if (xmlStrcmp(node->name, XMLSTR ("master-update-interval")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_update_interval = atoi(tmp);
@ -474,6 +469,14 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_ssl_port = atoi(tmp);
xmlFree (tmp);
} else if (xmlStrcmp(node->name, XMLSTR ("master-redirect")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_redirect = atoi(tmp);
xmlFree (tmp);
} else if (xmlStrcmp(node->name, XMLSTR ("max-redirect-slaves")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->max_redirects = atoi(tmp);
xmlFree (tmp);
} else if (xmlStrcmp(node->name, XMLSTR ("shoutcast-mount")) == 0) {
if (configuration->shoutcast_mount &&
configuration->shoutcast_mount != CONFIG_DEFAULT_SHOUTCAST_MOUNT)
@ -495,6 +498,8 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
_parse_security(doc, node->xmlChildrenNode, configuration);
}
} while ((node = node->next));
if (configuration->max_redirects == 0 && configuration->master_redirect)
configuration->max_redirects = 1;
}
static void _parse_limits(xmlDocPtr doc, xmlNodePtr node,

View File

@ -144,6 +144,8 @@ typedef struct ice_config_tag
char *master_password;
int master_relay_auth;
int master_ssl_port;
int master_redirect;
int max_redirects;
relay_server *relay;
@ -158,7 +160,6 @@ typedef struct ice_config_tag
char *adminroot_dir;
aliases *aliases;
unsigned slaves_count;
int master_redirect_port;
char *access_log;
char *error_log;

View File

@ -119,8 +119,6 @@ void client_destroy(client_t *client)
;
}
#endif
if (client->is_slave)
slave_host_remove (client);
if (client->con)
connection_close(client->con);
@ -171,12 +169,12 @@ int client_read_bytes (client_t *client, void *buf, unsigned len)
}
void client_send_302(client_t *client, char *location) {
void client_send_302(client_t *client, const char *location) {
snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
"HTTP/1.0 302 Temporarily Moved\r\n"
"Content-Type: text/html\r\n"
"Location: %s\r\n\r\n"
"<a href=\"%s\">%s</a>", location, location, location);
"Moved <a href=\"%s\">here</a>\r\n", location, location);
client->respcode = 302;
client->refbuf->len = strlen (client->refbuf->data);
fserve_add_client (client, NULL);
@ -296,16 +294,3 @@ void client_set_queue (client_t *client, refbuf_t *refbuf)
refbuf_release (to_release);
}
void client_as_slave (client_t *client)
{
char *slave_redirect = httpp_getvar (client->parser, "ice-redirect");
INFO1 ("client connected as slave from %s", client->con->ip);
client->is_slave = 1;
if (slave_redirect)
{
/* this will be something like ip:port */
DEBUG1 ("header for auth slave is \"%s\"", slave_redirect);
slave_host_add (client, slave_redirect);
}
}

View File

@ -92,10 +92,9 @@ void client_send_404(client_t *client, char *message);
void client_send_401(client_t *client);
void client_send_403(client_t *client, const char *reason);
void client_send_400(client_t *client, char *message);
void client_send_302(client_t *client, char *location);
void client_send_302(client_t *client, const char *location);
int client_send_bytes (client_t *client, const void *buf, unsigned len);
int client_read_bytes (client_t *client, void *buf, unsigned len);
void client_set_queue (client_t *client, refbuf_t *refbuf);
void client_as_slave (client_t *client);
#endif /* __CLIENT_H__ */

View File

@ -1227,7 +1227,7 @@ static void *_handle_connection(void *arg)
}
continue;
}
thread_sleep (50000);
thread_sleep (100000);
}
DEBUG0 ("Connection thread done");

View File

@ -90,8 +90,8 @@ int format_get_plugin (format_type_t type, source_t *source)
default:
break;
}
source->format->in_bitrate = rate_setup (10);
source->format->out_bitrate = rate_setup (10);
source->format->in_bitrate = rate_setup (30);
source->format->out_bitrate = rate_setup (30);
return ret;
}
@ -104,8 +104,10 @@ static void find_client_start (source_t *source, client_t *client)
{
refbuf_t *refbuf = source->burst_point;
/* we only want to attempt a burst at connection time, not midstream */
if (client->intro_offset == -1)
/* we only want to attempt a burst at connection time, not midstream
* however streams like theora may not have the most recent page marked as
* a starting point, so look for one from the burst point */
if (client->intro_offset == -1 && source->stream_data_tail->sync_point)
refbuf = source->stream_data_tail;
else
{

View File

@ -44,9 +44,9 @@ typedef struct ice_global_tag
/* relays retrieved from master */
struct _relay_server *master_relays;
/* slave relay list */
unsigned int slave_count;
struct _slave_host *slaves;
/* redirection to slaves */
unsigned int redirect_count;
struct _redirect_host *redirectors;
cond_t shutdown_cond;
} ice_global_t;

View File

@ -62,8 +62,9 @@
#define CATMODULE "slave"
static void *_slave_thread(void *arg);
static void _add_slave_host (const char *server, int port);
static slave_host *find_slave_host (const char *server, int port);
static void redirector_add (const char *server, int port, int interval);
static redirect_host *find_slave_host (const char *server, int port);
static void redirector_clearall (void);
static thread_type *_slave_thread_id;
static int slave_running = 0;
@ -140,6 +141,9 @@ void slave_initialize(void)
thread_rwlock_create (&slaves_lock);
slave_running = 1;
max_interval = 0;
#ifndef HAVE_CURL
WARN0 ("streamlist request disabled, rebuild with libcurl if required");
#endif
_slave_thread_id = thread_create("Slave Thread", _slave_thread, NULL, THREAD_ATTACHED);
}
@ -155,45 +159,60 @@ void slave_shutdown(void)
}
int slave_redirect (const char *mountpoint, client_t *client)
int redirect_client (const char *mountpoint, client_t *client)
{
slave_host *slave = NULL;
int ret = 0, which;
redirect_host *checking, **trail;
DEBUG1 ("slave count is %d", global.slave_count);
thread_rwlock_rlock (&slaves_lock);
/* select slave entry */
if (global.slave_count)
if (global.redirect_count == 0)
{
int which=(int) (((float)global.slave_count)*rand()/(RAND_MAX+1.0));
slave = global.slaves;
while (slave && which)
{
slave = slave->next;
which--;
}
DEBUG2 ("selected %s:%d", slave->server,slave->port);
thread_rwlock_unlock (&slaves_lock);
return 0;
}
if (slave)
{
char *location = NULL;
/* add 13 for "http://" the port ':' and nul */
int len = strlen(mountpoint) + strlen (slave->server) + 13;
which=(int) (((float)global.redirect_count)*rand()/(RAND_MAX+1.0)) + 1;
checking = global.redirectors;
trail = &global.redirectors;
location = malloc (len);
if (location)
DEBUG2 ("random selection %d (out of %d)", which, global.redirect_count);
while (checking)
{
DEBUG2 ("...%s:%d", checking->server, checking->port);
if (checking->next_update && checking->next_update+10 < global.time)
{
/* no streamist request, expire slave for now */
*trail = checking->next;
global.redirect_count--;
/* free slave details */
INFO2 ("dropping redirector for %s:%d", checking->server, checking->port);
free (checking->server);
free (checking);
checking = *trail;
if (which > 0)
which--; /* we are 1 less now */
continue;
}
if (--which == 0)
{
char *location;
/* add enough for "http://" the port ':' and nul */
int len = strlen (mountpoint) + strlen (checking->server) + 13;
INFO2 ("redirecting client to slave server "
"at %s:%d", slave->server, slave->port);
snprintf (location, len, "http://%s:%d%s", slave->server,
slave->port, mountpoint);
thread_rwlock_unlock (&slaves_lock);
"at %s:%d", checking->server, checking->port);
location = malloc (len);
snprintf (location, len, "http://%s:%d%s", checking->server,
checking->port, mountpoint);
client_send_302 (client, location);
free (location);
return 1;
ret = 1;
}
trail = &checking->next;
checking = checking->next;
}
thread_rwlock_unlock (&slaves_lock);
return 0;
return ret;
}
@ -214,7 +233,7 @@ static void *start_relay_stream (void *arg)
do
{
char *auth_header;
char *redirect_header = NULL, *server_id;
char *server_id;
ice_config_t *config;
streamsock = sock_connect_wto (relay->server, relay->port, 10);
@ -242,22 +261,10 @@ static void *start_relay_stream (void *arg)
snprintf (auth_header, len,
"Authorization: Basic %s\r\n", esc_authorisation);
free(esc_authorisation);
/* header to use for participating in load sharing */
if (config->master_redirect_port)
{
len = strlen ("ice-redirect:") + strlen (config->hostname) + 10;
redirect_header = malloc (len);
snprintf (redirect_header, len, "ice-redirect: %s:%d\r\n",
config->hostname, config->master_redirect_port);
}
else
redirect_header = strdup ("");
}
else
{
auth_header = strdup ("");
redirect_header = strdup ("");
}
config_release_config ();
@ -270,16 +277,13 @@ static void *start_relay_stream (void *arg)
"User-Agent: %s\r\n"
"%s"
"%s"
"%s"
"\r\n",
relay->mount,
server_id,
relay->mp3metadata?"Icy-MetaData: 1\r\n":"",
redirect_header,
auth_header);
free (server_id);
free (auth_header);
free (redirect_header);
memset (header, 0, sizeof(header));
if (util_read_header (con->sock, header, 4096, READ_ENTIRE_HEADER) == 0)
{
@ -380,7 +384,10 @@ static void check_relay_stream (relay_server *relay)
/* new relay, reserve the name */
relay->source = source_reserve (relay->localmount);
if (relay->source)
{
DEBUG1("Adding relay source at mountpoint \"%s\"", relay->localmount);
relay->cleanup = 1;
}
else
WARN1 ("new relay but source \"%s\" already exists", relay->localmount);
}
@ -395,16 +402,8 @@ static void check_relay_stream (relay_server *relay)
stats_event (relay->localmount, NULL, NULL);
break;
}
if (relay->on_demand)
if (relay->on_demand && source->on_demand_req == 0)
{
ice_config_t *config = config_get_config ();
mount_proxy *mountinfo = config_find_mount (config, relay->localmount);
if (mountinfo == NULL)
source_update_settings (config, relay->source, mountinfo);
config_release_config ();
slave_rebuild_mounts();
stats_event (relay->localmount, "listeners", "0");
relay->source->on_demand = relay->on_demand;
if (source->fallback_mount && source->fallback_override)
@ -431,11 +430,14 @@ static void check_relay_stream (relay_server *relay)
} while (0);
/* the relay thread may of shut down itself */
if (relay->cleanup && relay->thread)
if (relay->cleanup)
{
DEBUG1 ("waiting for relay thread for \"%s\"", relay->localmount);
thread_join (relay->thread);
relay->thread = NULL;
if (relay->thread)
{
DEBUG1 ("waiting for relay thread for \"%s\"", relay->localmount);
thread_join (relay->thread);
relay->thread = NULL;
}
relay->cleanup = 0;
relay->running = 0;
@ -541,7 +543,8 @@ update_relays (relay_server **relay_list, relay_server *new_relay_list)
}
static void relay_check_streams (relay_server *to_start, relay_server *to_free, int skip_timer)
static void relay_check_streams (relay_server *to_start,
relay_server *to_free, int skip_timer)
{
relay_server *relay;
@ -588,6 +591,7 @@ struct master_conn_details
char *username;
char *password;
char *server_id;
char *args;
relay_server *new_relays;
};
@ -701,7 +705,7 @@ static void *streamlist_thread (void *arg)
const char *protocol = "http";
int port = master->port;
char error [CURL_ERROR_SIZE];
char url [300], auth [100];
char url [1024], auth [100];
if (master->ssl_port)
{
@ -709,8 +713,8 @@ static void *streamlist_thread (void *arg)
port = master->ssl_port;
}
snprintf (auth, sizeof (auth), "%s:%s", master->username, master->password);
snprintf (url, sizeof (url), "%s://%s:%d/admin/streamlist.txt",
protocol, master->server, port);
snprintf (url, sizeof (url), "%s://%s:%d/admin/streamlist.txt%s",
protocol, master->server, port, master->args);
handle = curl_easy_init ();
curl_easy_setopt (handle, CURLOPT_USERAGENT, master->server_id);
curl_easy_setopt (handle, CURLOPT_URL, url);
@ -746,6 +750,7 @@ static void *streamlist_thread (void *arg)
free (master->password);
free (master->buffer);
free (master->server_id);
free (master->args);
free (master);
return NULL;
}
@ -769,24 +774,39 @@ static void update_from_master (ice_config_t *config)
details->send_auth = config->master_relay_auth;
details->on_demand = config->on_demand;
details->server_id = strdup (config->server_id);
if (config->master_redirect)
{
details->args = malloc (4096);
snprintf (details->args, 4096, "?rserver=%s&rport=%d&interval=%d",
config->hostname, config->port, config->master_update_interval);
}
else
details->args = strdup ("");
thread_create ("streamlist", streamlist_thread, details, THREAD_DETACHED);
#else
WARN0 ("streamlist request disabled, rebuild with libcurl if required");
#endif
}
static void update_master_as_slave (ice_config_t *config)
{
if (config->master_server == NULL || config->master_redirect_port == 0)
redirect_host *redirect;
if (config->master_server == NULL || config->master_redirect == 0 || config->max_redirects == 0)
{
redirector_clearall();
return;
}
thread_rwlock_wlock (&slaves_lock);
DEBUG1 ("redirect port is %d", config->master_redirect_port);
if (find_slave_host (config->master_server,
config->master_server_port) == NULL)
_add_slave_host (config->master_server, config->master_server_port);
redirect = find_slave_host (config->master_server, config->master_server_port);
if (redirect == NULL)
{
INFO2 ("adding master %s:%d", config->master_server, config->master_server_port);
redirector_add (config->master_server, config->master_server_port, 0);
}
else
redirect->next_update += max_interval;
thread_rwlock_unlock (&slaves_lock);
}
@ -852,6 +872,7 @@ static void *_slave_thread(void *arg)
INFO0 ("shutting down current relays");
relay_check_streams (NULL, global.relays, 0);
relay_check_streams (NULL, global.master_relays, 0);
redirector_clearall();
INFO0 ("Slave thread shutdown complete");
@ -871,108 +892,100 @@ relay_server *slave_find_relay (relay_server *relays, const char *mount)
}
/* remove this slave clients entry in the slave host list */
void slave_host_remove (client_t *client)
/* drop all redirection details.
*/
static void redirector_clearall (void)
{
const char *var = httpp_getvar (client->parser, "ice-redirect");
if (var)
thread_rwlock_wlock (&slaves_lock);
while (global.redirectors)
{
slave_host *slave, **trail;
char *server = strdup (var), *separator;
int port;
separator = strchr (server, ':');
if (separator == NULL)
{
free (server);
return;
}
*separator = '\0';
port = atoi (separator+1);
thread_rwlock_wlock (&slaves_lock);
slave = global.slaves;
trail = &global.slaves;
while (slave)
{
if (strcmp (slave->server, server) == 0 && slave->port == port)
{
slave->count--;
if (slave->count == 0)
{
INFO2 ("slave at %s:%d removed", slave->server, slave->port);
*trail = slave->next;
free (slave->server);
global.slave_count--;
}
break;
}
trail = &slave->next;
slave = slave->next;
}
thread_rwlock_unlock (&slaves_lock);
redirect_host *current = global.redirectors;
global.redirectors = current->next;
free (current->server);
free (current);
}
global.redirect_count = 0;
thread_rwlock_unlock (&slaves_lock);
}
/* with the provided header (eg "localhost:8000") add a new slave host
* entry to so that clients can redirect to other sites when full
/* Add new redirectors or update any existing ones
*/
void slave_host_add (client_t *client, const char *header)
void redirector_update (client_t *client)
{
slave_host *slave;
char *server, *separator;
int port;
redirect_host *redirect;
const char *rserver = httpp_get_query_param (client->parser, "rserver");
char *value;
int rport, interval;
if (rserver==NULL) return;
value = httpp_get_query_param (client->parser, "rport");
if (value == NULL) return;
rport = atoi (value);
if (rport <= 0) return;
value = httpp_get_query_param (client->parser, "interval");
if (value == NULL) return;
interval = atoi (value);
if (interval < 5) return;
if (client == NULL || header == NULL)
return;
server = strdup (header);
separator = strchr (server, ':');
if (separator == NULL)
{
free (server);
return;
}
*separator = '\0';
port = atoi (separator+1);
thread_rwlock_wlock (&slaves_lock);
slave = find_slave_host (server, port);
if (slave)
redirect = find_slave_host (rserver, rport);
if (redirect == NULL)
{
slave->count++;
DEBUG0 ("already exists, increasing count");
redirector_add (rserver, rport, interval);
}
else
_add_slave_host (server, port);
thread_rwlock_unlock (&slaves_lock);
free (server);
}
static slave_host *find_slave_host (const char *server, int port)
{
slave_host *slave = global.slaves;
while (slave)
{
if (strcmp (slave->server, server) == 0 && slave->port == port)
break;
slave = slave->next;
DEBUG2 ("touch update on %s:%d", redirect->server, redirect->port);
redirect->next_update = global.time + interval;
}
return slave;
thread_rwlock_unlock (&slaves_lock);
}
static void _add_slave_host (const char *server, int port)
/* search list of redirectors for a matching entry, lock must be held before
* invoking this function
*/
static redirect_host *find_slave_host (const char *server, int port)
{
slave_host *slave = calloc (1, sizeof (slave_host));
if (slave == NULL)
return;
slave->server = strdup (server);
slave->port = port;
slave->count = 1;
slave->next = global.slaves;
global.slaves = slave;
global.slave_count++;
INFO3 ("slave (%d) at %s:%d added", global.slave_count,
slave->server, slave->port);
redirect_host *redirect = global.redirectors;
while (redirect)
{
if (strcmp (redirect->server, server) == 0 && redirect->port == port)
break;
redirect = redirect->next;
}
return redirect;
}
static void redirector_add (const char *server, int port, int interval)
{
ice_config_t *config = config_get_config();
int allowed = config->max_redirects;
redirect_host *redirect;
config_release_config();
if (global.redirect_count >= allowed)
{
INFO1 ("redirect to slave limit reached (%d)", global.redirect_count);
return;
}
redirect = calloc (1, sizeof (redirect_host));
if (redirect == NULL)
abort();
redirect->server = strdup (server);
redirect->port = port;
if (interval == 0)
redirect->next_update = (time_t)0;
else
redirect->next_update = global.time + interval;
redirect->next = global.redirectors;
global.redirectors = redirect;
global.redirect_count++;
INFO3 ("slave (%d) at %s:%d added", global.redirect_count,
redirect->server, redirect->port);
}

View File

@ -35,22 +35,21 @@ typedef struct _relay_server {
struct _relay_server *next;
} relay_server;
typedef struct _slave_host
typedef struct _redirect_host
{
char *server;
int port;
unsigned int count;
struct _slave_host *next;
} slave_host;
time_t next_update;
struct _redirect_host *next;
} redirect_host;
void slave_initialize(void);
void slave_shutdown(void);
void slave_recheck_mounts (void);
void slave_rebuild_mounts (void);
relay_server *slave_find_relay (relay_server *relays, const char *mount);
int slave_redirect (const char *mountpoint, struct _client_tag *client);
void slave_host_add (struct _client_tag *client, const char *header);
void slave_host_remove (struct _client_tag *client);
int redirect_client (const char *mountpoint, struct _client_tag *client);
void redirector_update (struct _client_tag *client);
relay_server *relay_free (relay_server *relay);
#endif /* __SLAVE_H__ */

View File

@ -436,16 +436,18 @@ static void get_next_buffer (source_t *source)
/* take the lock */
thread_mutex_lock (&source->lock);
if (current >= source->client_stats_update)
if (source->client && current >= source->client_stats_update)
{
stats_event_args (source->mount, "outgoing_bitrate", "%ld",
8 * rate_avg (source->format->out_bitrate));
(8 * rate_avg (source->format->out_bitrate))/1000);
stats_event_args (source->mount, "incoming_bitrate", "%ld",
8 * rate_avg (source->format->in_bitrate));
(8 * rate_avg (source->format->in_bitrate))/1000);
stats_event_args (source->mount, "total_bytes_read",
FORMAT_UINT64, source->format->read_bytes);
stats_event_args (source->mount, "total_bytes_sent",
FORMAT_UINT64, source->format->sent_bytes);
stats_event_args (source->mount, "connected", FORMAT_UINT64,
(uint64_t)(current - source->client->con->con_time));
source->client_stats_update = current + 5;
}
if (fds < 0)

View File

@ -91,6 +91,7 @@ static int yp_running;
static time_t now;
static thread_type *yp_thread;
static volatile unsigned client_limit = 0;
static volatile char *server_version = NULL;
static void *yp_update_thread(void *arg);
static void add_yp_info (ypdata_t *yp, void *info, int type);
@ -217,6 +218,8 @@ void yp_recheck_config (ice_config_t *config)
server = server->next;
}
client_limit = config->client_limit;
free (server_version);
server_version = strdup (config->server_id);
/* for each yp url in config, check to see if one exists
if not, then add it. */
for (i=0 ; i < config->num_yp_directories; i++)
@ -242,7 +245,7 @@ void yp_recheck_config (ice_config_t *config)
}
if (server->touch_interval < 30)
server->touch_interval = 30;
curl_easy_setopt (server->curl, CURLOPT_USERAGENT, ICECAST_VERSION_STRING);
curl_easy_setopt (server->curl, CURLOPT_USERAGENT, server_version);
curl_easy_setopt (server->curl, CURLOPT_URL, server->url);
curl_easy_setopt (server->curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
curl_easy_setopt (server->curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
@ -354,6 +357,8 @@ static unsigned do_yp_add (ypdata_t *yp, char *s, unsigned len)
free (value);
value = stats_get_value (yp->mount, "bitrate");
if (value == NULL)
value = stats_get_value (yp->mount, "incoming_bitrate");
add_yp_info (yp, value, YP_BITRATE);
free (value);
@ -845,7 +850,7 @@ void yp_add (const char *mount)
yp->server = server;
yp->touch_interval = server->touch_interval;
yp->next = server->pending_mounts;
yp->next_update = time(NULL) + 5;
yp->next_update = global.time + 60;
server->pending_mounts = yp;
yp_update = 1;
}
@ -925,6 +930,8 @@ void yp_shutdown (void)
if (yp_thread)
thread_join (yp_thread);
curl_global_cleanup();
free (server_version);
server_version = NULL;
INFO0 ("YP thread down");
}