mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-02-02 15:07:36 -05:00
infrastructure for new web-based admin interface
new config option <adminroot> restructured code a bit in admin.c for a bit better extendability svn path=/trunk/icecast/; revision=4708
This commit is contained in:
parent
6c05e292fc
commit
27c0af2b1d
452
src/admin.c
452
src/admin.c
@ -2,6 +2,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <libxml/xmlmemory.h>
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
@ -11,6 +14,7 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "format_mp3.h"
|
#include "format_mp3.h"
|
||||||
@ -22,61 +26,198 @@
|
|||||||
#define COMMAND_ERROR (-1)
|
#define COMMAND_ERROR (-1)
|
||||||
|
|
||||||
/* Mount-specific commands */
|
/* Mount-specific commands */
|
||||||
#define COMMAND_FALLBACK 1
|
#define COMMAND_RAW_FALLBACK 1
|
||||||
#define COMMAND_METADATA_UPDATE 2
|
#define COMMAND_METADATA_UPDATE 2
|
||||||
#define COMMAND_SHOW_LISTENERS 3
|
#define COMMAND_RAW_SHOW_LISTENERS 3
|
||||||
#define COMMAND_MOVE_CLIENTS 4
|
#define COMMAND_RAW_MOVE_CLIENTS 4
|
||||||
|
|
||||||
|
#define COMMAND_TRANSFORMED_FALLBACK 50
|
||||||
|
#define COMMAND_TRANSFORMED_SHOW_LISTENERS 53
|
||||||
|
#define COMMAND_TRANSFORMED_MOVE_CLIENTS 54
|
||||||
|
|
||||||
/* Global commands */
|
/* Global commands */
|
||||||
#define COMMAND_LIST_MOUNTS 101
|
#define COMMAND_RAW_LIST_MOUNTS 101
|
||||||
#define COMMAND_RAW_STATS 102
|
#define COMMAND_RAW_STATS 102
|
||||||
#define COMMAND_RAW_LISTSTREAM 103
|
#define COMMAND_RAW_LISTSTREAM 103
|
||||||
|
#define COMMAND_TRANSFORMED_LIST_MOUNTS 201
|
||||||
|
#define COMMAND_TRANSFORMED_STATS 202
|
||||||
|
#define COMMAND_TRANSFORMED_LISTSTREAM 203
|
||||||
|
|
||||||
/* Client management commands */
|
/* Client management commands */
|
||||||
#define COMMAND_KILL_CLIENT 201
|
#define COMMAND_RAW_KILL_CLIENT 301
|
||||||
#define COMMAND_KILL_SOURCE 202
|
#define COMMAND_RAW_KILL_SOURCE 302
|
||||||
|
#define COMMAND_TRANSFORMED_KILL_CLIENT 401
|
||||||
|
#define COMMAND_TRANSFORMED_KILL_SOURCE 402
|
||||||
|
|
||||||
|
#define FALLBACK_RAW_REQUEST "fallbacks"
|
||||||
|
#define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl"
|
||||||
|
#define METADATA_REQUEST "metadata"
|
||||||
|
#define LISTCLIENTS_RAW_REQUEST "listclients"
|
||||||
|
#define LISTCLIENTS_TRANSFORMED_REQUEST "listclients.xsl"
|
||||||
|
#define STATS_RAW_REQUEST "stats"
|
||||||
|
#define STATS_TRANSFORMED_REQUEST "stats.xsl"
|
||||||
|
#define LISTMOUNTS_RAW_REQUEST "listmounts"
|
||||||
|
#define LISTMOUNTS_TRANSFORMED_REQUEST "listmounts.xsl"
|
||||||
|
#define STREAMLIST_RAW_REQUEST "streamlist"
|
||||||
|
#define STREAMLIST_TRANSFORMED_REQUEST "streamlist.xsl"
|
||||||
|
#define MOVECLIENTS_RAW_REQUEST "moveclients"
|
||||||
|
#define MOVECLIENTS_TRANSFORMED_REQUEST "moveclients.xsl"
|
||||||
|
#define KILLCLIENT_RAW_REQUEST "killclient"
|
||||||
|
#define KILLCLIENT_TRANSFORMED_REQUEST "killclient.xsl"
|
||||||
|
#define KILLSOURCE_RAW_REQUEST "killsource"
|
||||||
|
#define KILLSOURCE_TRANSFORMED_REQUEST "killsource.xsl"
|
||||||
|
#define ADMIN_XSL_RESPONSE "response.xsl"
|
||||||
|
#define DEFAULT_RAW_REQUEST ""
|
||||||
|
#define DEFAULT_TRANSFORMED_REQUEST ""
|
||||||
|
|
||||||
|
#define RAW 1
|
||||||
|
#define TRANSFORMED 2
|
||||||
int admin_get_command(char *command)
|
int admin_get_command(char *command)
|
||||||
{
|
{
|
||||||
if(!strcmp(command, "fallbacks"))
|
if(!strcmp(command, FALLBACK_RAW_REQUEST))
|
||||||
return COMMAND_FALLBACK;
|
return COMMAND_RAW_FALLBACK;
|
||||||
else if(!strcmp(command, "metadata"))
|
else if(!strcmp(command, FALLBACK_TRANSFORMED_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_FALLBACK;
|
||||||
|
else if(!strcmp(command, METADATA_REQUEST))
|
||||||
return COMMAND_METADATA_UPDATE;
|
return COMMAND_METADATA_UPDATE;
|
||||||
else if(!strcmp(command, "listclients"))
|
else if(!strcmp(command, LISTCLIENTS_RAW_REQUEST))
|
||||||
return COMMAND_SHOW_LISTENERS;
|
return COMMAND_RAW_SHOW_LISTENERS;
|
||||||
else if(!strcmp(command, "rawstats"))
|
else if(!strcmp(command, LISTCLIENTS_TRANSFORMED_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_SHOW_LISTENERS;
|
||||||
|
else if(!strcmp(command, STATS_RAW_REQUEST))
|
||||||
return COMMAND_RAW_STATS;
|
return COMMAND_RAW_STATS;
|
||||||
|
else if(!strcmp(command, STATS_TRANSFORMED_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_STATS;
|
||||||
else if(!strcmp(command, "stats.xml")) /* The old way */
|
else if(!strcmp(command, "stats.xml")) /* The old way */
|
||||||
return COMMAND_RAW_STATS;
|
return COMMAND_RAW_STATS;
|
||||||
else if(!strcmp(command, "listmounts"))
|
else if(!strcmp(command, LISTMOUNTS_RAW_REQUEST))
|
||||||
return COMMAND_LIST_MOUNTS;
|
return COMMAND_RAW_LIST_MOUNTS;
|
||||||
else if(!strcmp(command, "streamlist"))
|
else if(!strcmp(command, LISTMOUNTS_TRANSFORMED_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_LIST_MOUNTS;
|
||||||
|
else if(!strcmp(command, STREAMLIST_RAW_REQUEST))
|
||||||
return COMMAND_RAW_LISTSTREAM;
|
return COMMAND_RAW_LISTSTREAM;
|
||||||
else if(!strcmp(command, "moveclients"))
|
else if(!strcmp(command, MOVECLIENTS_RAW_REQUEST))
|
||||||
return COMMAND_MOVE_CLIENTS;
|
return COMMAND_RAW_MOVE_CLIENTS;
|
||||||
else if(!strcmp(command, "killclient"))
|
else if(!strcmp(command, MOVECLIENTS_TRANSFORMED_REQUEST))
|
||||||
return COMMAND_KILL_CLIENT;
|
return COMMAND_TRANSFORMED_MOVE_CLIENTS;
|
||||||
else if(!strcmp(command, "killsource"))
|
else if(!strcmp(command, KILLCLIENT_RAW_REQUEST))
|
||||||
return COMMAND_KILL_SOURCE;
|
return COMMAND_RAW_KILL_CLIENT;
|
||||||
|
else if(!strcmp(command, KILLCLIENT_TRANSFORMED_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_KILL_CLIENT;
|
||||||
|
else if(!strcmp(command, KILLSOURCE_RAW_REQUEST))
|
||||||
|
return COMMAND_RAW_KILL_SOURCE;
|
||||||
|
else if(!strcmp(command, KILLSOURCE_TRANSFORMED_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_KILL_SOURCE;
|
||||||
|
else if(!strcmp(command, DEFAULT_TRANSFORMED_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_STATS;
|
||||||
|
else if(!strcmp(command, DEFAULT_RAW_REQUEST))
|
||||||
|
return COMMAND_TRANSFORMED_STATS;
|
||||||
else
|
else
|
||||||
return COMMAND_ERROR;
|
return COMMAND_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_fallback(client_t *client, source_t *source);
|
static void command_fallback(client_t *client, source_t *source, int response);
|
||||||
static void command_metadata(client_t *client, source_t *source);
|
static void command_metadata(client_t *client, source_t *source);
|
||||||
static void command_show_listeners(client_t *client, source_t *source);
|
static void command_show_listeners(client_t *client, source_t *source,
|
||||||
static void command_move_clients(client_t *client, source_t *source);
|
int response);
|
||||||
|
static void command_move_clients(client_t *client, source_t *source,
|
||||||
static void command_raw_stats(client_t *client);
|
int response);
|
||||||
static void command_list_mounts(client_t *client, int formatted);
|
static void command_stats(client_t *client, int response);
|
||||||
|
static void command_list_mounts(client_t *client, int response);
|
||||||
static void command_kill_client(client_t *client, source_t *source);
|
static void command_kill_client(client_t *client, source_t *source,
|
||||||
static void command_kill_source(client_t *client, source_t *source);
|
int response);
|
||||||
|
static void command_kill_source(client_t *client, source_t *source,
|
||||||
|
int response);
|
||||||
static void admin_handle_mount_request(client_t *client, source_t *source,
|
static void admin_handle_mount_request(client_t *client, source_t *source,
|
||||||
int command);
|
int command);
|
||||||
static void admin_handle_general_request(client_t *client, int command);
|
static void admin_handle_general_request(client_t *client, int command);
|
||||||
|
static void admin_send_response(xmlDocPtr doc, client_t *client,
|
||||||
|
int response, char *xslt_template);
|
||||||
|
static void html_write(client_t *client, char *fmt, ...);
|
||||||
|
|
||||||
|
xmlDocPtr admin_build_sourcelist(char *current_source)
|
||||||
|
{
|
||||||
|
avl_node *node;
|
||||||
|
source_t *source;
|
||||||
|
xmlNodePtr xmlnode, srcnode;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
char buf[22];
|
||||||
|
int len = 0;
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
doc = xmlNewDoc("1.0");
|
||||||
|
xmlnode = xmlNewDocNode(doc, NULL, "icestats", NULL);
|
||||||
|
xmlDocSetRootElement(doc, xmlnode);
|
||||||
|
|
||||||
|
if (current_source) {
|
||||||
|
xmlNewChild(xmlnode, NULL, "current_source", current_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_tree_rlock(global.source_tree);
|
||||||
|
|
||||||
|
node = avl_get_first(global.source_tree);
|
||||||
|
while(node) {
|
||||||
|
source = (source_t *)node->key;
|
||||||
|
srcnode = xmlNewChild(xmlnode, NULL, "source", NULL);
|
||||||
|
xmlSetProp(srcnode, "mount", source->mount);
|
||||||
|
|
||||||
|
xmlNewChild(srcnode, NULL, "fallback",
|
||||||
|
(source->fallback_mount != NULL)?
|
||||||
|
source->fallback_mount:"");
|
||||||
|
memset(buf, '\000', sizeof(buf));
|
||||||
|
snprintf(buf, sizeof(buf)-1, "%d", source->listeners);
|
||||||
|
xmlNewChild(srcnode, NULL, "listeners", buf);
|
||||||
|
memset(buf, '\000', sizeof(buf));
|
||||||
|
snprintf(buf, sizeof(buf)-1, "%d", now - source->con->con_time);
|
||||||
|
xmlNewChild(srcnode, NULL, "Connected", buf);
|
||||||
|
xmlNewChild(srcnode, NULL, "Format",
|
||||||
|
source->format->format_description);
|
||||||
|
node = avl_get_next(node);
|
||||||
|
}
|
||||||
|
avl_tree_unlock(global.source_tree);
|
||||||
|
return(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void admin_send_response(xmlDocPtr doc, client_t *client,
|
||||||
|
int response, char *xslt_template)
|
||||||
|
{
|
||||||
|
char *buff = NULL;
|
||||||
|
int len = 0;
|
||||||
|
ice_config_t *config;
|
||||||
|
char *fullpath_xslt_template;
|
||||||
|
int fullpath_xslt_template_len;
|
||||||
|
char *adminwebroot;
|
||||||
|
|
||||||
|
client->respcode = 200;
|
||||||
|
if (response == RAW) {
|
||||||
|
xmlDocDumpMemory(doc, (xmlChar **)&buff, &len);
|
||||||
|
html_write(client, "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"Content-Type: text/xml\r\n"
|
||||||
|
"\r\n", len);
|
||||||
|
html_write(client, buff);
|
||||||
|
}
|
||||||
|
if (response == TRANSFORMED) {
|
||||||
|
config = config_get_config();
|
||||||
|
adminwebroot = config->adminroot_dir;
|
||||||
|
config_release_config();
|
||||||
|
fullpath_xslt_template_len = strlen(adminwebroot) +
|
||||||
|
strlen(xslt_template) + 2;
|
||||||
|
fullpath_xslt_template = malloc(fullpath_xslt_template_len);
|
||||||
|
memset(fullpath_xslt_template, '\000', fullpath_xslt_template_len);
|
||||||
|
snprintf(fullpath_xslt_template, fullpath_xslt_template_len, "%s%s%s",
|
||||||
|
adminwebroot, PATH_SEPARATOR, xslt_template);
|
||||||
|
html_write(client, "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"\r\n");
|
||||||
|
DEBUG1("Sending XSLT (%s)", fullpath_xslt_template);
|
||||||
|
xslt_transform(doc, fullpath_xslt_template, client);
|
||||||
|
free(fullpath_xslt_template);
|
||||||
|
}
|
||||||
|
if (buff) {
|
||||||
|
xmlFree(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
void admin_handle_request(client_t *client, char *uri)
|
void admin_handle_request(client_t *client, char *uri)
|
||||||
{
|
{
|
||||||
char *mount, *command_string;
|
char *mount, *command_string;
|
||||||
@ -90,6 +231,7 @@ void admin_handle_request(client_t *client, char *uri)
|
|||||||
|
|
||||||
command_string = uri + 7;
|
command_string = uri + 7;
|
||||||
|
|
||||||
|
DEBUG1("Got command (%s)", command_string);
|
||||||
command = admin_get_command(command_string);
|
command = admin_get_command(command_string);
|
||||||
|
|
||||||
if(command < 0) {
|
if(command < 0) {
|
||||||
@ -147,13 +289,25 @@ static void admin_handle_general_request(client_t *client, int command)
|
|||||||
{
|
{
|
||||||
switch(command) {
|
switch(command) {
|
||||||
case COMMAND_RAW_STATS:
|
case COMMAND_RAW_STATS:
|
||||||
command_raw_stats(client);
|
command_stats(client, RAW);
|
||||||
break;
|
break;
|
||||||
case COMMAND_LIST_MOUNTS:
|
case COMMAND_RAW_LIST_MOUNTS:
|
||||||
command_list_mounts(client, 1);
|
command_list_mounts(client, RAW);
|
||||||
break;
|
break;
|
||||||
case COMMAND_RAW_LISTSTREAM:
|
case COMMAND_RAW_LISTSTREAM:
|
||||||
command_list_mounts(client, 0);
|
command_list_mounts(client, RAW);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_STATS:
|
||||||
|
command_stats(client, TRANSFORMED);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_LIST_MOUNTS:
|
||||||
|
command_list_mounts(client, TRANSFORMED);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_LISTSTREAM:
|
||||||
|
command_list_mounts(client, TRANSFORMED);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_MOVE_CLIENTS:
|
||||||
|
command_list_mounts(client, TRANSFORMED);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN0("General admin request not recognised");
|
WARN0("General admin request not recognised");
|
||||||
@ -166,23 +320,38 @@ static void admin_handle_mount_request(client_t *client, source_t *source,
|
|||||||
int command)
|
int command)
|
||||||
{
|
{
|
||||||
switch(command) {
|
switch(command) {
|
||||||
case COMMAND_FALLBACK:
|
case COMMAND_RAW_FALLBACK:
|
||||||
command_fallback(client, source);
|
command_fallback(client, source, RAW);
|
||||||
break;
|
break;
|
||||||
case COMMAND_METADATA_UPDATE:
|
case COMMAND_METADATA_UPDATE:
|
||||||
command_metadata(client, source);
|
command_metadata(client, source);
|
||||||
break;
|
break;
|
||||||
case COMMAND_SHOW_LISTENERS:
|
case COMMAND_RAW_SHOW_LISTENERS:
|
||||||
command_show_listeners(client, source);
|
command_show_listeners(client, source, RAW);
|
||||||
break;
|
break;
|
||||||
case COMMAND_MOVE_CLIENTS:
|
case COMMAND_RAW_MOVE_CLIENTS:
|
||||||
command_move_clients(client, source);
|
command_move_clients(client, source, RAW);
|
||||||
break;
|
break;
|
||||||
case COMMAND_KILL_CLIENT:
|
case COMMAND_RAW_KILL_CLIENT:
|
||||||
command_kill_client(client, source);
|
command_kill_client(client, source, RAW);
|
||||||
break;
|
break;
|
||||||
case COMMAND_KILL_SOURCE:
|
case COMMAND_RAW_KILL_SOURCE:
|
||||||
command_kill_source(client, source);
|
command_kill_source(client, source, RAW);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_FALLBACK:
|
||||||
|
command_fallback(client, source, RAW);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_SHOW_LISTENERS:
|
||||||
|
command_show_listeners(client, source, TRANSFORMED);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_MOVE_CLIENTS:
|
||||||
|
command_move_clients(client, source, TRANSFORMED);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_KILL_CLIENT:
|
||||||
|
command_kill_client(client, source, TRANSFORMED);
|
||||||
|
break;
|
||||||
|
case COMMAND_TRANSFORMED_KILL_SOURCE:
|
||||||
|
command_kill_source(client, source, TRANSFORMED);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN0("Mount request not recognised");
|
WARN0("Mount request not recognised");
|
||||||
@ -199,6 +368,8 @@ static void admin_handle_mount_request(client_t *client, source_t *source,
|
|||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
#define COMMAND_OPTIONAL(client,name,var) \
|
||||||
|
(var) = httpp_get_query_param((client)->parser, (name))
|
||||||
|
|
||||||
static void html_success(client_t *client, char *message)
|
static void html_success(client_t *client, char *message)
|
||||||
{
|
{
|
||||||
@ -238,14 +409,31 @@ static void html_write(client_t *client, char *fmt, ...)
|
|||||||
if(bytes > 0) client->con->sent_bytes = bytes;
|
if(bytes > 0) client->con->sent_bytes = bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_move_clients(client_t *client, source_t *source)
|
static void command_move_clients(client_t *client, source_t *source,
|
||||||
|
int response)
|
||||||
{
|
{
|
||||||
char *dest_source;
|
char *dest_source;
|
||||||
source_t *dest;
|
source_t *dest;
|
||||||
avl_node *client_node;
|
avl_node *client_node;
|
||||||
client_t *current;
|
client_t *current;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlNodePtr node;
|
||||||
|
char buf[255];
|
||||||
|
int parameters_passed = 0;
|
||||||
|
|
||||||
COMMAND_REQUIRE(client, "destination", dest_source);
|
DEBUG0("Doing optional check");
|
||||||
|
if (COMMAND_OPTIONAL(client, "destination", dest_source)) {
|
||||||
|
parameters_passed = 1;
|
||||||
|
}
|
||||||
|
DEBUG1("Done optional check (%d)", parameters_passed);
|
||||||
|
if (!parameters_passed) {
|
||||||
|
doc = admin_build_sourcelist(source->mount);
|
||||||
|
admin_send_response(doc, client, response,
|
||||||
|
MOVECLIENTS_TRANSFORMED_REQUEST);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
client_destroy(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
avl_tree_rlock(global.source_tree);
|
avl_tree_rlock(global.source_tree);
|
||||||
dest = source_find_mount(dest_source);
|
dest = source_find_mount(dest_source);
|
||||||
@ -256,6 +444,10 @@ static void command_move_clients(client_t *client, source_t *source)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doc = xmlNewDoc("1.0");
|
||||||
|
node = xmlNewDocNode(doc, NULL, "iceresponse", NULL);
|
||||||
|
xmlDocSetRootElement(doc, node);
|
||||||
|
|
||||||
avl_tree_wlock(source->client_tree);
|
avl_tree_wlock(source->client_tree);
|
||||||
client_node = avl_get_first(source->client_tree);
|
client_node = avl_get_first(source->client_tree);
|
||||||
while(client_node) {
|
while(client_node) {
|
||||||
@ -268,57 +460,104 @@ static void command_move_clients(client_t *client, source_t *source)
|
|||||||
client_node = avl_get_next(client_node);
|
client_node = avl_get_next(client_node);
|
||||||
|
|
||||||
avl_delete(source->client_tree, current, source_remove_client);
|
avl_delete(source->client_tree, current, source_remove_client);
|
||||||
|
source->listeners--;
|
||||||
}
|
}
|
||||||
|
|
||||||
avl_tree_unlock(source->client_tree);
|
avl_tree_unlock(source->client_tree);
|
||||||
|
|
||||||
html_success(client, "Clients moved");
|
memset(buf, '\000', sizeof(buf));
|
||||||
|
snprintf(buf, sizeof(buf)-1, "Clients moved from %s to %s", dest_source,
|
||||||
|
source->mount);
|
||||||
|
xmlNewChild(node, NULL, "message", buf);
|
||||||
|
xmlNewChild(node, NULL, "return", "1");
|
||||||
|
|
||||||
|
admin_send_response(doc, client, response,
|
||||||
|
ADMIN_XSL_RESPONSE);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
client_destroy(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_show_listeners(client_t *client, source_t *source)
|
static void command_show_listeners(client_t *client, source_t *source,
|
||||||
|
int response)
|
||||||
{
|
{
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlNodePtr node, srcnode, listenernode;
|
||||||
avl_node *client_node;
|
avl_node *client_node;
|
||||||
client_t *current;
|
client_t *current;
|
||||||
|
char buf[22];
|
||||||
|
int len = 0;
|
||||||
|
char *userAgent = NULL;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
DEBUG1("Dumping listeners on mountpoint %s", source->mount);
|
doc = xmlNewDoc("1.0");
|
||||||
|
node = xmlNewDocNode(doc, NULL, "icestats", NULL);
|
||||||
|
srcnode = xmlNewChild(node, NULL, "source", NULL);
|
||||||
|
xmlSetProp(srcnode, "mount", source->mount);
|
||||||
|
xmlDocSetRootElement(doc, node);
|
||||||
|
|
||||||
html_head(client);
|
memset(buf, '\000', sizeof(buf));
|
||||||
|
snprintf(buf, sizeof(buf)-1, "%d", source->listeners);
|
||||||
html_write(client,
|
xmlNewChild(srcnode, NULL, "Listeners", buf);
|
||||||
"<table><tr><td>IP</td><td>Connected</td><td>ID</td></tr>");
|
|
||||||
|
|
||||||
avl_tree_rlock(source->client_tree);
|
avl_tree_rlock(source->client_tree);
|
||||||
|
|
||||||
client_node = avl_get_first(source->client_tree);
|
client_node = avl_get_first(source->client_tree);
|
||||||
while(client_node) {
|
while(client_node) {
|
||||||
current = (client_t *)client_node->key;
|
current = (client_t *)client_node->key;
|
||||||
|
listenernode = xmlNewChild(srcnode, NULL, "listener", NULL);
|
||||||
html_write(client, "<tr><td>%s</td><td>%d</td><td>%ld</td></tr>",
|
xmlNewChild(listenernode, NULL, "IP", current->con->ip);
|
||||||
current->con->ip, now-current->con->con_time, current->con->id);
|
userAgent = httpp_getvar(current->parser, "user-agent");
|
||||||
|
if (userAgent) {
|
||||||
|
xmlNewChild(listenernode, NULL, "UserAgent", userAgent);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
xmlNewChild(listenernode, NULL, "UserAgent", "Unknown");
|
||||||
|
}
|
||||||
|
memset(buf, '\000', sizeof(buf));
|
||||||
|
snprintf(buf, sizeof(buf)-1, "%d", now - current->con->con_time);
|
||||||
|
xmlNewChild(listenernode, NULL, "Connected", buf);
|
||||||
|
memset(buf, '\000', sizeof(buf));
|
||||||
|
snprintf(buf, sizeof(buf)-1, "%d", current->con->id);
|
||||||
|
xmlNewChild(listenernode, NULL, "ID", buf);
|
||||||
client_node = avl_get_next(client_node);
|
client_node = avl_get_next(client_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
avl_tree_unlock(source->client_tree);
|
avl_tree_unlock(source->client_tree);
|
||||||
|
admin_send_response(doc, client, response,
|
||||||
html_write(client, "</table></body></html>");
|
LISTCLIENTS_TRANSFORMED_REQUEST);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
client_destroy(client);
|
client_destroy(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_kill_source(client_t *client, source_t *source)
|
static void command_kill_source(client_t *client, source_t *source,
|
||||||
|
int response)
|
||||||
{
|
{
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlNodePtr node;
|
||||||
|
|
||||||
|
doc = xmlNewDoc("1.0");
|
||||||
|
node = xmlNewDocNode(doc, NULL, "iceresponse", NULL);
|
||||||
|
xmlNewChild(node, NULL, "message", "Source Removed");
|
||||||
|
xmlNewChild(node, NULL, "return", "1");
|
||||||
|
xmlDocSetRootElement(doc, node);
|
||||||
|
|
||||||
source->running = 0;
|
source->running = 0;
|
||||||
|
|
||||||
html_success(client, "Removing source");
|
admin_send_response(doc, client, response,
|
||||||
|
ADMIN_XSL_RESPONSE);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
client_destroy(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_kill_client(client_t *client, source_t *source)
|
static void command_kill_client(client_t *client, source_t *source,
|
||||||
|
int response)
|
||||||
{
|
{
|
||||||
char *idtext;
|
char *idtext;
|
||||||
int id;
|
int id;
|
||||||
client_t *listener;
|
client_t *listener;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlNodePtr node;
|
||||||
|
char buf[50] = "";
|
||||||
|
|
||||||
COMMAND_REQUIRE(client, "id", idtext);
|
COMMAND_REQUIRE(client, "id", idtext);
|
||||||
|
|
||||||
@ -326,6 +565,11 @@ static void command_kill_client(client_t *client, source_t *source)
|
|||||||
|
|
||||||
listener = source_find_client(source, id);
|
listener = source_find_client(source, id);
|
||||||
|
|
||||||
|
doc = xmlNewDoc("1.0");
|
||||||
|
node = xmlNewDocNode(doc, NULL, "iceresponse", NULL);
|
||||||
|
xmlDocSetRootElement(doc, node);
|
||||||
|
DEBUG1("Response is %d", response);
|
||||||
|
|
||||||
if(listener != NULL) {
|
if(listener != NULL) {
|
||||||
INFO1("Admin request: client %d removed", id);
|
INFO1("Admin request: client %d removed", id);
|
||||||
|
|
||||||
@ -333,15 +577,25 @@ static void command_kill_client(client_t *client, source_t *source)
|
|||||||
* loop
|
* loop
|
||||||
*/
|
*/
|
||||||
listener->con->error = 1;
|
listener->con->error = 1;
|
||||||
|
memset(buf, '\000', sizeof(buf));
|
||||||
html_success(client, "Client removed");
|
snprintf(buf, sizeof(buf)-1, "Client %d removed", id);
|
||||||
|
xmlNewChild(node, NULL, "message", buf);
|
||||||
|
xmlNewChild(node, NULL, "return", "1");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
html_success(client, "Client not found");
|
memset(buf, '\000', sizeof(buf));
|
||||||
|
snprintf(buf, sizeof(buf)-1, "Client %d not found", id);
|
||||||
|
xmlNewChild(node, NULL, "message", buf);
|
||||||
|
xmlNewChild(node, NULL, "return", "0");
|
||||||
}
|
}
|
||||||
|
admin_send_response(doc, client, response,
|
||||||
|
ADMIN_XSL_RESPONSE);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
client_destroy(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_fallback(client_t *client, source_t *source)
|
static void command_fallback(client_t *client, source_t *source,
|
||||||
|
int response)
|
||||||
{
|
{
|
||||||
char *fallback;
|
char *fallback;
|
||||||
char *old;
|
char *old;
|
||||||
@ -387,69 +641,41 @@ static void command_metadata(client_t *client, source_t *source)
|
|||||||
state->metadata_raw = 0;
|
state->metadata_raw = 0;
|
||||||
thread_mutex_unlock(&(state->lock));
|
thread_mutex_unlock(&(state->lock));
|
||||||
|
|
||||||
DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value);
|
DEBUG2("Metadata on mountpoint %s changed to \"%s\"",
|
||||||
|
source->mount, value);
|
||||||
stats_event(source->mount, "title", value);
|
stats_event(source->mount, "title", value);
|
||||||
|
|
||||||
html_success(client, "Metadata update successful");
|
html_success(client, "Metadata update successful");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_raw_stats(client_t *client) {
|
static void command_stats(client_t *client, int response) {
|
||||||
|
xmlDocPtr doc;
|
||||||
|
|
||||||
DEBUG0("Stats request, sending xml stats");
|
DEBUG0("Stats request, sending xml stats");
|
||||||
|
|
||||||
stats_sendxml(client);
|
stats_get_xml(&doc);
|
||||||
|
admin_send_response(doc, client, response, STATS_TRANSFORMED_REQUEST);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
client_destroy(client);
|
client_destroy(client);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_list_mounts(client_t *client, int formatted) {
|
static void command_list_mounts(client_t *client, int response) {
|
||||||
avl_node *node;
|
avl_node *node;
|
||||||
source_t *source;
|
source_t *source;
|
||||||
int bytes;
|
int bytes;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlNodePtr xmlnode, srcnode, datanode;
|
||||||
|
char buf[22];
|
||||||
|
int len = 0;
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
DEBUG0("List mounts request");
|
DEBUG0("List mounts request");
|
||||||
|
|
||||||
if(formatted) {
|
doc = admin_build_sourcelist(NULL);
|
||||||
html_head(client);
|
|
||||||
|
|
||||||
html_write(client,
|
|
||||||
"<table><tr><td>Mountpoint</td><td>Fallback</td>"
|
|
||||||
"<td>Format</td><td>Listeners</td></tr>");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
client->respcode = 200;
|
|
||||||
bytes = sock_write(client->con->sock,
|
|
||||||
"HTTP/1.0 200 OK\r\n"
|
|
||||||
"Content-Type: text/html\r\n"
|
|
||||||
"\r\n");
|
|
||||||
if(bytes > 0) client->con->sent_bytes = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
avl_tree_rlock(global.source_tree);
|
|
||||||
|
|
||||||
node = avl_get_first(global.source_tree);
|
|
||||||
while(node) {
|
|
||||||
source = (source_t *)node->key;
|
|
||||||
|
|
||||||
if(formatted) {
|
|
||||||
html_write(client,
|
|
||||||
"<tr><td>%s</td><td>%s</td><td>%s</td><td>%ld</td></tr>",
|
|
||||||
source->mount, (source->fallback_mount != NULL)?
|
|
||||||
source->fallback_mount:"",
|
|
||||||
source->format->format_description, source->listeners);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bytes = sock_write(client->con->sock, "%s\r\n", source->mount);
|
|
||||||
if(bytes > 0) client->con->sent_bytes += bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = avl_get_next(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
avl_tree_unlock(global.source_tree);
|
|
||||||
|
|
||||||
if(formatted)
|
|
||||||
html_write(client, "</table></body></html>");
|
|
||||||
|
|
||||||
|
admin_send_response(doc, client, response, LISTMOUNTS_TRANSFORMED_REQUEST);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
client_destroy(client);
|
client_destroy(client);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
11
src/config.c
11
src/config.c
@ -40,10 +40,12 @@
|
|||||||
#define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast"
|
#define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast"
|
||||||
#define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs"
|
#define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs"
|
||||||
#define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot"
|
#define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot"
|
||||||
|
#define CONFIG_DEFAULT_ADMINROOT_DIR "/usr/local/icecast/admin"
|
||||||
#else
|
#else
|
||||||
#define CONFIG_DEFAULT_BASE_DIR ".\\"
|
#define CONFIG_DEFAULT_BASE_DIR ".\\"
|
||||||
#define CONFIG_DEFAULT_LOG_DIR ".\\logs"
|
#define CONFIG_DEFAULT_LOG_DIR ".\\logs"
|
||||||
#define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot"
|
#define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot"
|
||||||
|
#define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ice_config_t _current_configuration;
|
ice_config_t _current_configuration;
|
||||||
@ -122,6 +124,8 @@ void config_clear(ice_config_t *c)
|
|||||||
xmlFree(c->log_dir);
|
xmlFree(c->log_dir);
|
||||||
if (c->webroot_dir && c->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR)
|
if (c->webroot_dir && c->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR)
|
||||||
xmlFree(c->webroot_dir);
|
xmlFree(c->webroot_dir);
|
||||||
|
if (c->adminroot_dir && c->adminroot_dir != CONFIG_DEFAULT_ADMINROOT_DIR)
|
||||||
|
xmlFree(c->adminroot_dir);
|
||||||
if (c->access_log && c->access_log != CONFIG_DEFAULT_ACCESS_LOG)
|
if (c->access_log && c->access_log != CONFIG_DEFAULT_ACCESS_LOG)
|
||||||
xmlFree(c->access_log);
|
xmlFree(c->access_log);
|
||||||
if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG)
|
if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG)
|
||||||
@ -284,6 +288,7 @@ static void _set_defaults(ice_config_t *configuration)
|
|||||||
configuration->base_dir = CONFIG_DEFAULT_BASE_DIR;
|
configuration->base_dir = CONFIG_DEFAULT_BASE_DIR;
|
||||||
configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
|
configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
|
||||||
configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR;
|
configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR;
|
||||||
|
configuration->adminroot_dir = CONFIG_DEFAULT_ADMINROOT_DIR;
|
||||||
configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG;
|
configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG;
|
||||||
configuration->error_log = CONFIG_DEFAULT_ERROR_LOG;
|
configuration->error_log = CONFIG_DEFAULT_ERROR_LOG;
|
||||||
configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
|
configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
|
||||||
@ -638,6 +643,12 @@ static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
|
if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
|
||||||
configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
|
configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
|
||||||
|
} else if (strcmp(node->name, "adminroot") == 0) {
|
||||||
|
if (configuration->adminroot_dir && configuration->adminroot_dir != CONFIG_DEFAULT_WEBROOT_DIR)
|
||||||
|
xmlFree(configuration->adminroot_dir);
|
||||||
|
configuration->adminroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
|
if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
|
||||||
|
configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
|
||||||
} else if (strcmp(node->name, "alias") == 0) {
|
} else if (strcmp(node->name, "alias") == 0) {
|
||||||
alias = malloc(sizeof(aliases));
|
alias = malloc(sizeof(aliases));
|
||||||
alias->next = NULL;
|
alias->next = NULL;
|
||||||
|
@ -97,6 +97,7 @@ typedef struct ice_config_tag
|
|||||||
char *base_dir;
|
char *base_dir;
|
||||||
char *log_dir;
|
char *log_dir;
|
||||||
char *webroot_dir;
|
char *webroot_dir;
|
||||||
|
char *adminroot_dir;
|
||||||
aliases *aliases;
|
aliases *aliases;
|
||||||
|
|
||||||
char *access_log;
|
char *access_log;
|
||||||
|
@ -552,6 +552,8 @@ void *source_main(void *arg)
|
|||||||
client_node = avl_get_first(source->pending_tree);
|
client_node = avl_get_first(source->pending_tree);
|
||||||
while (client_node) {
|
while (client_node) {
|
||||||
avl_insert(source->client_tree, client_node->key);
|
avl_insert(source->client_tree, client_node->key);
|
||||||
|
/* listener count may have changed */
|
||||||
|
listeners = source->listeners;
|
||||||
listeners++;
|
listeners++;
|
||||||
DEBUG0("Client added");
|
DEBUG0("Client added");
|
||||||
stats_event_inc(NULL, "clients");
|
stats_event_inc(NULL, "clients");
|
||||||
|
Loading…
Reference in New Issue
Block a user