Commit e8a61ce5 authored by Ed "oddsock" Zaleski's avatar Ed "oddsock" Zaleski

fixed master-slave relaying...

* slaves now ask for /admin/streamlist.txt which serves a plaintext version of the source list (this is what it was expecting to get)
* /admin/streamlist still serves XML (which slave.c wasn't expecting)
* fixed a few cases of pointer invalidation due to possible config re-reading.
* slave relay now uses relay password to get the list of streams to relay

svn path=/trunk/icecast/; revision=5695
parent bb96da29
......@@ -47,6 +47,7 @@
#define COMMAND_RAW_LIST_MOUNTS 101
#define COMMAND_RAW_STATS 102
#define COMMAND_RAW_LISTSTREAM 103
#define COMMAND_PLAINTEXT_LISTSTREAM 104
#define COMMAND_TRANSFORMED_LIST_MOUNTS 201
#define COMMAND_TRANSFORMED_STATS 202
#define COMMAND_TRANSFORMED_LISTSTREAM 203
......@@ -68,6 +69,7 @@
#define LISTMOUNTS_TRANSFORMED_REQUEST "listmounts.xsl"
#define STREAMLIST_RAW_REQUEST "streamlist"
#define STREAMLIST_TRANSFORMED_REQUEST "streamlist.xsl"
#define STREAMLIST_PLAINTEXT_REQUEST "streamlist.txt"
#define MOVECLIENTS_RAW_REQUEST "moveclients"
#define MOVECLIENTS_TRANSFORMED_REQUEST "moveclients.xsl"
#define KILLCLIENT_RAW_REQUEST "killclient"
......@@ -80,6 +82,7 @@
#define RAW 1
#define TRANSFORMED 2
#define PLAINTEXT 3
int admin_get_command(char *command)
{
if(!strcmp(command, FALLBACK_RAW_REQUEST))
......@@ -104,6 +107,8 @@ int admin_get_command(char *command)
return COMMAND_TRANSFORMED_LIST_MOUNTS;
else if(!strcmp(command, STREAMLIST_RAW_REQUEST))
return COMMAND_RAW_LISTSTREAM;
else if(!strcmp(command, STREAMLIST_PLAINTEXT_REQUEST))
return COMMAND_PLAINTEXT_LISTSTREAM;
else if(!strcmp(command, MOVECLIENTS_RAW_REQUEST))
return COMMAND_RAW_MOVE_CLIENTS;
else if(!strcmp(command, MOVECLIENTS_TRANSFORMED_REQUEST))
......@@ -281,11 +286,24 @@ void admin_handle_request(client_t *client, char *uri)
}
else {
if(!connection_check_admin_pass(client->parser)) {
INFO1("Bad or missing password on admin command "
"request (command: %s)", command_string);
client_send_401(client);
return;
if (command == COMMAND_PLAINTEXT_LISTSTREAM) {
/* this request is used by a slave relay to retrieve
mounts from the master, so handle this request
validating against the relay password */
if(!connection_check_relay_pass(client->parser)) {
INFO1("Bad or missing password on admin command "
"request (command: %s)", command_string);
client_send_401(client);
return;
}
}
else {
if(!connection_check_admin_pass(client->parser)) {
INFO1("Bad or missing password on admin command "
"request (command: %s)", command_string);
client_send_401(client);
return;
}
}
admin_handle_general_request(client, command);
......@@ -304,6 +322,9 @@ static void admin_handle_general_request(client_t *client, int command)
case COMMAND_RAW_LISTSTREAM:
command_list_mounts(client, RAW);
break;
case COMMAND_PLAINTEXT_LISTSTREAM:
command_list_mounts(client, PLAINTEXT);
break;
case COMMAND_TRANSFORMED_STATS:
command_stats(client, TRANSFORMED);
break;
......@@ -668,14 +689,35 @@ static void command_stats(client_t *client, int response) {
static void command_list_mounts(client_t *client, int response) {
xmlDocPtr doc;
avl_node *node;
source_t *source;
DEBUG0("List mounts request");
doc = admin_build_sourcelist(NULL);
admin_send_response(doc, client, response, LISTMOUNTS_TRANSFORMED_REQUEST);
xmlFreeDoc(doc);
if (response == PLAINTEXT) {
avl_tree_rlock(global.source_tree);
node = avl_get_first(global.source_tree);
html_write(client,
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
while(node) {
source = (source_t *)node->key;
html_write(client, "%s\n", source->mount);
node = avl_get_next(node);
}
avl_tree_unlock(global.source_tree);
}
else {
doc = admin_build_sourcelist(NULL);
admin_send_response(doc, client, response,
LISTMOUNTS_TRANSFORMED_REQUEST);
xmlFreeDoc(doc);
}
client_destroy(client);
return;
}
......@@ -120,6 +120,10 @@ void config_clear(ice_config_t *c)
xmlFree(c->admin_username);
if (c->admin_password)
xmlFree(c->admin_password);
if (c->relay_username)
xmlFree(c->relay_username);
if (c->relay_password)
xmlFree(c->relay_password);
if (c->hostname && c->hostname != CONFIG_DEFAULT_HOSTNAME)
xmlFree(c->hostname);
if (c->base_dir && c->base_dir != CONFIG_DEFAULT_BASE_DIR)
......@@ -302,6 +306,8 @@ static void _set_defaults(ice_config_t *configuration)
configuration->user = CONFIG_DEFAULT_USER;
configuration->group = CONFIG_DEFAULT_GROUP;
configuration->num_yp_directories = 0;
configuration->relay_username = NULL;
configuration->relay_password = NULL;
}
static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
......@@ -593,6 +599,16 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
xmlFree(configuration->admin_username);
configuration->admin_username =
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (strcmp(node->name, "relay-password") == 0) {
if(configuration->relay_password)
xmlFree(configuration->relay_password);
configuration->relay_password =
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (strcmp(node->name, "relay-user") == 0) {
if(configuration->relay_username)
xmlFree(configuration->relay_username);
configuration->relay_username =
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
}
} while ((node = node->next));
}
......
......@@ -76,6 +76,8 @@ typedef struct ice_config_tag
char *source_password;
char *admin_username;
char *admin_password;
char *relay_username;
char *relay_password;
int touch_interval;
ice_config_dir_t *dir_list;
......
......@@ -557,15 +557,35 @@ static int _check_pass_ice(http_parser_t *parser, char *correctpass)
int connection_check_admin_pass(http_parser_t *parser)
{
int ret;
ice_config_t *config = config_get_config();
char *pass = config->admin_password;
char *user = config->admin_username;
if(!pass || !user) {
config_release_config();
return 0;
}
ret = _check_pass_http(parser, user, pass);
config_release_config();
return ret;
}
int connection_check_relay_pass(http_parser_t *parser)
{
int ret;
ice_config_t *config = config_get_config();
char *pass = config->relay_password;
char *user = "relay";
if(!pass || !user)
if(!pass || !user) {
config_release_config();
return 0;
}
return _check_pass_http(parser, user, pass);
ret = _check_pass_http(parser, user, pass);
config_release_config();
return ret;
}
int connection_check_source_pass(http_parser_t *parser, char *mount)
......@@ -579,7 +599,6 @@ int connection_check_source_pass(http_parser_t *parser, char *mount)
mount_proxy *mountinfo = config->mounts;
thread_mutex_lock(&(config_locks()->mounts_lock));
config_release_config();
while(mountinfo) {
if(!strcmp(mountinfo->mountname, mount)) {
......@@ -596,6 +615,7 @@ int connection_check_source_pass(http_parser_t *parser, char *mount)
if(!pass) {
WARN0("No source password set, rejecting source");
config_release_config();
return 0;
}
......@@ -612,6 +632,7 @@ int connection_check_source_pass(http_parser_t *parser, char *mount)
WARN0("Source is using deprecated icecast login");
}
}
config_release_config();
return ret;
}
......
......@@ -95,22 +95,16 @@ static void create_relay_stream(char *server, int port,
return;
}
con = create_connection(streamsock, -1, NULL);
if(mp3) {
/* Some mp3 servers are bitchy, send a user-agent string to make them
* send the right response.
*/
sock_write(streamsock, "GET %s HTTP/1.0\r\n"
"User-Agent: " ICECAST_VERSION_STRING "\r\n"
"Icy-MetaData: 1\r\n"
"\r\n",
remotemount);
}
else {
sock_write(streamsock, "GET %s HTTP/1.0\r\n"
"User-Agent: " ICECAST_VERSION_STRING "\r\n"
"\r\n",
remotemount);
}
/* At this point we may not know if we are relaying a mp3 or vorbis stream,
* so lets send in the icy-metadata header just in case, it's harmless in
* the vorbis case. If we don't send in this header then relay will not
* have mp3 metadata.
*/
sock_write(streamsock, "GET %s HTTP/1.0\r\n"
"User-Agent: " ICECAST_VERSION_STRING "\r\n"
"Icy-MetaData: 1\r\n"
"\r\n",
remotemount);
memset(header, 0, sizeof(header));
if (util_read_header(con->sock, header, 4096) == 0) {
WARN0("Header read failed");
......@@ -198,7 +192,7 @@ static void *_slave_thread(void *arg) {
strcat(authheader, password);
data = util_base64_encode(authheader);
sock_write(mastersock,
"GET /admin/streamlist HTTP/1.0\r\n"
"GET /admin/streamlist.txt HTTP/1.0\r\n"
"Authorization: Basic %s\r\n"
"\r\n", data);
free(authheader);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment