mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-02-02 15:07:36 -05:00
Merge branch 'ph3-devel-module-links'
This commit is contained in:
commit
1773e723c0
@ -14,6 +14,11 @@
|
||||
<ul>
|
||||
<li class="on"><a href="/admin/stats.xsl">Administration</a></li>
|
||||
<li><a href="/admin/listmounts.xsl">Mountpoint list</a></li>
|
||||
<xsl:for-each select="(/report/extension/icestats | /icestats | /iceresponse)/modules/module">
|
||||
<xsl:if test="@management-url and @management-title">
|
||||
<li><a href="{@management-url}"><xsl:value-of select="@management-title" /></a></li>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
<li><a href="/status.xsl">Public area</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
31
src/admin.c
31
src/admin.c
@ -317,6 +317,17 @@ int admin_command_table_unregister(const char *prefix)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* build an XML root node including some common tags */
|
||||
xmlNodePtr admin_build_rootnode(xmlDocPtr doc, const char *name)
|
||||
{
|
||||
xmlNodePtr rootnode = xmlNewDocNode(doc, NULL, XMLSTR(name), NULL);
|
||||
xmlNodePtr modules = module_container_get_modulelist_as_xml(global.modulecontainer);
|
||||
|
||||
xmlAddChild(rootnode, modules);
|
||||
|
||||
return rootnode;
|
||||
}
|
||||
|
||||
/* build an XML doc containing information about currently running sources.
|
||||
* If a mountpoint is passed then that source will not be added to the XML
|
||||
* doc even if the source is running */
|
||||
@ -330,7 +341,7 @@ xmlDocPtr admin_build_sourcelist(const char *mount)
|
||||
time_t now = time(NULL);
|
||||
|
||||
doc = xmlNewDoc (XMLSTR("1.0"));
|
||||
xmlnode = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL);
|
||||
xmlnode = admin_build_rootnode(doc, "icestats");
|
||||
xmlDocSetRootElement(doc, xmlnode);
|
||||
|
||||
if (mount) {
|
||||
@ -649,7 +660,7 @@ static void command_move_clients(client_t *client,
|
||||
ICECAST_LOG_INFO("source is \"%s\", destination is \"%s\"", source->mount, dest->mount);
|
||||
|
||||
doc = xmlNewDoc(XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
|
||||
node = admin_build_rootnode(doc, "iceresponse");
|
||||
xmlDocSetRootElement(doc, node);
|
||||
|
||||
source_move_clients(source, dest);
|
||||
@ -744,7 +755,7 @@ static void command_show_listeners(client_t *client,
|
||||
char buf[22];
|
||||
|
||||
doc = xmlNewDoc(XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
|
||||
node = admin_build_rootnode(doc, "icestats");
|
||||
srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL);
|
||||
xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount));
|
||||
xmlDocSetRootElement(doc, node);
|
||||
@ -902,12 +913,12 @@ static void command_manageauth(client_t *client, source_t *source, admin_format_
|
||||
}
|
||||
|
||||
doc = xmlNewDoc(XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
|
||||
node = admin_build_rootnode(doc, "icestats");
|
||||
|
||||
rolenode = admin_add_role_to_authentication(auth, node);
|
||||
|
||||
if (message) {
|
||||
msgnode = xmlNewChild(node, NULL, XMLSTR("iceresponse"), NULL);
|
||||
msgnode = admin_build_rootnode(doc, "iceresponse");
|
||||
xmlNewTextChild(msgnode, NULL, XMLSTR("message"), XMLSTR(message));
|
||||
}
|
||||
|
||||
@ -941,7 +952,7 @@ static void command_kill_source(client_t *client,
|
||||
xmlNodePtr node;
|
||||
|
||||
doc = xmlNewDoc (XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
|
||||
node = admin_build_rootnode(doc, "iceresponse");
|
||||
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR("Source Removed"));
|
||||
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
|
||||
xmlDocSetRootElement(doc, node);
|
||||
@ -971,7 +982,7 @@ static void command_kill_client(client_t *client,
|
||||
listener = source_find_client(source, id);
|
||||
|
||||
doc = xmlNewDoc(XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
|
||||
node = admin_build_rootnode(doc, "iceresponse");
|
||||
xmlDocSetRootElement(doc, node);
|
||||
ICECAST_LOG_DEBUG("Response is %d", response);
|
||||
|
||||
@ -1028,7 +1039,7 @@ static void command_metadata(client_t *client,
|
||||
int same_ip = 1;
|
||||
|
||||
doc = xmlNewDoc(XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
|
||||
node = admin_build_rootnode(doc, "iceresponse");
|
||||
xmlDocSetRootElement(doc, node);
|
||||
|
||||
ICECAST_LOG_DEBUG("Got metadata update request");
|
||||
@ -1155,7 +1166,7 @@ static void command_queue_reload(client_t *client, source_t *source, admin_forma
|
||||
global_unlock();
|
||||
|
||||
doc = xmlNewDoc (XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
|
||||
node = admin_build_rootnode(doc, "iceresponse");
|
||||
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR("Config reload queued"));
|
||||
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
|
||||
xmlDocSetRootElement(doc, node);
|
||||
@ -1207,7 +1218,7 @@ static void command_updatemetadata(client_t *client,
|
||||
xmlNodePtr node, srcnode;
|
||||
|
||||
doc = xmlNewDoc(XMLSTR("1.0"));
|
||||
node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
|
||||
node = admin_build_rootnode(doc, "icestats");
|
||||
srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL);
|
||||
xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount));
|
||||
xmlDocSetRootElement(doc, node);
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "compat.h"
|
||||
#include "resourcematch.h"
|
||||
|
||||
#define ADMIN_ICESTATS_LEGACY_EXTENSION_APPLICATION "http://icecast.org/specs/legacy-icestats"
|
||||
|
||||
/* types */
|
||||
#define ADMINTYPE_ERROR (-1)
|
||||
#define ADMINTYPE_GENERAL 1
|
||||
|
93
src/client.c
93
src/client.c
@ -24,6 +24,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include "common/thread/thread.h"
|
||||
#include "common/avl/avl.h"
|
||||
#include "common/httpp/httpp.h"
|
||||
@ -51,7 +53,7 @@
|
||||
#include "listensocket.h"
|
||||
#include "fastevent.h"
|
||||
|
||||
/* for ADMIN_COMMAND_ERROR */
|
||||
/* for ADMIN_COMMAND_ERROR, and ADMIN_ICESTATS_LEGACY_EXTENSION_APPLICATION */
|
||||
#include "admin.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -301,7 +303,6 @@ int client_read_bytes(client_t *client, void *buf, unsigned len)
|
||||
|
||||
static inline void _client_send_error(client_t *client, const icecast_error_t *error)
|
||||
{
|
||||
ice_config_t *config;
|
||||
reportxml_t *report;
|
||||
admin_format_t admin_format;
|
||||
const char *xslt = NULL;
|
||||
@ -323,28 +324,8 @@ static inline void _client_send_error(client_t *client, const icecast_error_t *e
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
config = config_get_config();
|
||||
report = reportxml_database_build_report(config->reportxml_db, error->uuid, -1);
|
||||
config_release_config();
|
||||
|
||||
if (!report) {
|
||||
reportxml_node_t *root, *incident, *state, *text;
|
||||
|
||||
report = reportxml_new();
|
||||
root = reportxml_get_root_node(report);
|
||||
incident = reportxml_node_new(REPORTXML_NODE_TYPE_INCIDENT, NULL, NULL, NULL);
|
||||
state = reportxml_node_new(REPORTXML_NODE_TYPE_STATE, NULL, error->uuid, NULL);
|
||||
text = reportxml_node_new(REPORTXML_NODE_TYPE_TEXT, NULL, NULL, NULL);
|
||||
reportxml_node_set_content(text, error->message);
|
||||
reportxml_node_add_child(state, text);
|
||||
reportxml_node_add_child(incident, state);
|
||||
reportxml_node_add_child(root, incident);
|
||||
refobject_unref(text);
|
||||
refobject_unref(state);
|
||||
refobject_unref(incident);
|
||||
refobject_unref(root);
|
||||
}
|
||||
report = client_get_reportxml(error->uuid, NULL, error->message);
|
||||
|
||||
client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, xslt, admin_format, error->http_status);
|
||||
|
||||
@ -623,6 +604,72 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
|
||||
static void client_get_reportxml__add_basic_stats(reportxml_t *report)
|
||||
{
|
||||
reportxml_node_t *rootnode, *extension;
|
||||
xmlNodePtr xmlroot;
|
||||
xmlNodePtr modules;
|
||||
|
||||
rootnode = reportxml_get_root_node(report);
|
||||
|
||||
extension = reportxml_node_new(REPORTXML_NODE_TYPE_EXTENSION, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(extension, "application", ADMIN_ICESTATS_LEGACY_EXTENSION_APPLICATION);
|
||||
|
||||
reportxml_node_add_child(rootnode, extension);
|
||||
|
||||
refobject_unref(rootnode);
|
||||
|
||||
xmlroot = xmlNewNode(NULL, XMLSTR("icestats"));
|
||||
modules = module_container_get_modulelist_as_xml(global.modulecontainer);
|
||||
xmlAddChild(xmlroot, modules);
|
||||
|
||||
|
||||
reportxml_node_add_xml_child(extension, xmlroot);
|
||||
refobject_unref(extension);
|
||||
xmlFreeNode(xmlroot);
|
||||
}
|
||||
|
||||
reportxml_t *client_get_reportxml(const char *state_definition, const char *state_akindof, const char *state_text)
|
||||
{
|
||||
reportxml_t *report = NULL;
|
||||
|
||||
if (state_definition) {
|
||||
ice_config_t *config;
|
||||
|
||||
config = config_get_config();
|
||||
report = reportxml_database_build_report(config->reportxml_db, state_definition, -1);
|
||||
config_release_config();
|
||||
}
|
||||
|
||||
if (!report) {
|
||||
reportxml_node_t *rootnode, *incidentnode, *statenode;
|
||||
|
||||
report = reportxml_new();
|
||||
rootnode = reportxml_get_root_node(report);
|
||||
incidentnode = reportxml_node_new(REPORTXML_NODE_TYPE_INCIDENT, NULL, NULL, NULL);
|
||||
statenode = reportxml_node_new(REPORTXML_NODE_TYPE_STATE, NULL, state_definition, state_akindof);
|
||||
|
||||
if (state_text) {
|
||||
reportxml_node_t *textnode;
|
||||
|
||||
textnode = reportxml_node_new(REPORTXML_NODE_TYPE_TEXT, NULL, NULL, NULL);
|
||||
reportxml_node_set_content(textnode, state_text);
|
||||
reportxml_node_add_child(statenode, textnode);
|
||||
refobject_unref(textnode);
|
||||
}
|
||||
|
||||
reportxml_node_add_child(incidentnode, statenode);
|
||||
reportxml_node_add_child(rootnode, incidentnode);
|
||||
refobject_unref(statenode);
|
||||
refobject_unref(incidentnode);
|
||||
refobject_unref(rootnode);
|
||||
}
|
||||
|
||||
client_get_reportxml__add_basic_stats(report);
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client)
|
||||
{
|
||||
const char *pref;
|
||||
|
@ -144,6 +144,7 @@ void client_send_101(client_t *client, reuse_t reuse);
|
||||
void client_send_204(client_t *client);
|
||||
void client_send_426(client_t *client, reuse_t reuse);
|
||||
void client_send_reportxml(client_t *client, reportxml_t *report, document_domain_t domain, const char *xsl, admin_format_t admin_format_hint, int status);
|
||||
reportxml_t *client_get_reportxml(const char *state_definition, const char *state_akindof, const char *state_text);
|
||||
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client);
|
||||
int client_send_bytes (client_t *client, const void *buf, unsigned len);
|
||||
int client_read_bytes (client_t *client, void *buf, unsigned len);
|
||||
|
73
src/module.c
73
src/module.c
@ -18,6 +18,7 @@
|
||||
|
||||
#include "refobject.h"
|
||||
#include "module.h"
|
||||
#include "cfgfile.h" /* for XMLSTR() */
|
||||
|
||||
struct module_tag {
|
||||
refobject_base_t __base;
|
||||
@ -26,6 +27,8 @@ struct module_tag {
|
||||
size_t client_handlers_len;
|
||||
module_setup_handler_t freecb;
|
||||
void *userdata;
|
||||
char *management_link_url;
|
||||
char *management_link_title;
|
||||
};
|
||||
|
||||
|
||||
@ -118,6 +121,37 @@ module_t * module_container_get_module(module_container_t *self, co
|
||||
return ret;
|
||||
}
|
||||
|
||||
xmlNodePtr module_container_get_modulelist_as_xml(module_container_t *self)
|
||||
{
|
||||
xmlNodePtr root;
|
||||
avl_node *avlnode;
|
||||
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
root = xmlNewNode(NULL, XMLSTR("modules"));
|
||||
if (!root)
|
||||
return NULL;
|
||||
|
||||
thread_mutex_lock(&(self->lock));
|
||||
avlnode = avl_get_first(self->module);
|
||||
while (avlnode) {
|
||||
module_t *module = avlnode->key;
|
||||
xmlNodePtr node = xmlNewChild(root, NULL, XMLSTR("module"), NULL);
|
||||
|
||||
xmlSetProp(node, XMLSTR("name"), XMLSTR(refobject_get_name(module)));
|
||||
if (module->management_link_url)
|
||||
xmlSetProp(node, XMLSTR("management-url"), XMLSTR(module->management_link_url));
|
||||
if (module->management_link_title)
|
||||
xmlSetProp(node, XMLSTR("management-title"), XMLSTR(module->management_link_title));
|
||||
|
||||
avlnode = avl_get_next(avlnode);
|
||||
}
|
||||
thread_mutex_unlock(&(self->lock));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static void __module_free(refobject_t self, void **userdata)
|
||||
{
|
||||
module_t *mod = REFOBJECT_TO_TYPE(self, module_t *);
|
||||
@ -128,6 +162,9 @@ static void __module_free(refobject_t self, void **userdata)
|
||||
if (mod->userdata)
|
||||
free(mod->userdata);
|
||||
|
||||
free(mod->management_link_url);
|
||||
free(mod->management_link_title);
|
||||
|
||||
thread_mutex_destroy(&(mod->lock));
|
||||
}
|
||||
|
||||
@ -153,6 +190,42 @@ module_t * module_new(const char *name, module_setup_handler_t newc
|
||||
return ret;
|
||||
}
|
||||
|
||||
int module_add_link(module_t *self, const char *type, const char *url, const char *title)
|
||||
{
|
||||
char *n_url = NULL;
|
||||
char *n_title = NULL;
|
||||
|
||||
if (!self || !type)
|
||||
return -1;
|
||||
|
||||
if (strcmp(type, "management-url") != 0)
|
||||
return -1;
|
||||
|
||||
if (url) {
|
||||
n_url = strdup(url);
|
||||
if (!n_url)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (title) {
|
||||
n_title = strdup(title);
|
||||
if (!n_title) {
|
||||
free(n_url);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
thread_mutex_lock(&(self->lock));
|
||||
free(self->management_link_url);
|
||||
free(self->management_link_title);
|
||||
|
||||
self->management_link_url = n_url;
|
||||
self->management_link_title = n_title;
|
||||
thread_mutex_unlock(&(self->lock));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const module_client_handler_t * module_get_client_handler(module_t *self, const char *name)
|
||||
{
|
||||
size_t i;
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef __MODULE_H__
|
||||
#define __MODULE_H__
|
||||
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include "icecasttypes.h"
|
||||
|
||||
typedef void (*module_client_handler_function_t)(module_t *self, client_t *client, const char *uri);
|
||||
@ -23,9 +25,12 @@ module_container_t * module_container_new(void);
|
||||
int module_container_add_module(module_container_t *self, module_t *module);
|
||||
int module_container_delete_module(module_container_t *self, const char *name);
|
||||
module_t * module_container_get_module(module_container_t *self, const char *name);
|
||||
xmlNodePtr module_container_get_modulelist_as_xml(module_container_t *self);
|
||||
|
||||
module_t * module_new(const char *name, module_setup_handler_t newcb, module_setup_handler_t freecb, void *userdata);
|
||||
|
||||
int module_add_link(module_t *self, const char *type, const char *url, const char *title);
|
||||
|
||||
/* Note: Those functions are not really thread safe as (module_client_handler_t) is not thread safe. This is by design. */
|
||||
const module_client_handler_t * module_get_client_handler(module_t *self, const char *name);
|
||||
int module_add_client_handler(module_t *self, const module_client_handler_t *handlers, size_t len);
|
||||
|
@ -286,6 +286,14 @@ reportxml_node_t * reportxml_get_node_by_attribute(reportxml_t *report, con
|
||||
return reportxml_node_get_child_by_attribute(report->root, key, value, include_definitions);
|
||||
}
|
||||
|
||||
reportxml_node_t * reportxml_get_node_by_type(reportxml_t *report, reportxml_node_type_t type, int include_definitions)
|
||||
{
|
||||
if (!report)
|
||||
return NULL;
|
||||
|
||||
return reportxml_node_get_child_by_type(report->root, type, include_definitions);
|
||||
}
|
||||
|
||||
reportxml_t * reportxml_parse_xmldoc(xmlDocPtr doc)
|
||||
{
|
||||
reportxml_node_t *root;
|
||||
@ -822,6 +830,33 @@ reportxml_node_t * reportxml_node_get_child_by_attribute(reportxml_node_t *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reportxml_node_t * reportxml_node_get_child_by_type(reportxml_node_t *node, reportxml_node_type_t type, int include_definitions)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
if (node->type == type) {
|
||||
if (refobject_ref(node) != 0)
|
||||
return NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
if (node->type == REPORTXML_NODE_TYPE_DEFINITION && !include_definitions)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < node->childs_len; i++) {
|
||||
reportxml_node_t *ret;
|
||||
|
||||
ret = reportxml_node_get_child_by_type(node->childs[i], type, include_definitions);
|
||||
if (ret != NULL)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int reportxml_node_set_content(reportxml_node_t *node, const char *value)
|
||||
{
|
||||
const struct nodedef *nodedef;
|
||||
|
@ -77,6 +77,8 @@ reportxml_node_t * reportxml_get_root_node(reportxml_t *report);
|
||||
* <definition>s are skipped.
|
||||
*/
|
||||
reportxml_node_t * reportxml_get_node_by_attribute(reportxml_t *report, const char *key, const char *value, int include_definitions);
|
||||
/* This gets a node by it's type. Otherwise identical to reportxml_get_node_by_attribute() */
|
||||
reportxml_node_t * reportxml_get_node_by_type(reportxml_t *report, reportxml_node_type_t type, int include_definitions);
|
||||
/* This function parses an XML document and returns the parst report XML document */
|
||||
reportxml_t * reportxml_parse_xmldoc(xmlDocPtr doc);
|
||||
/* This function renders an report XML document as XML structure */
|
||||
@ -108,6 +110,8 @@ ssize_t reportxml_node_count_child(reportxml_node_t *node);
|
||||
reportxml_node_t * reportxml_node_get_child(reportxml_node_t *node, size_t idx);
|
||||
/* This gets an child by it's value of the given attribute. See reportxml_get_node_by_attribute() for more details. */
|
||||
reportxml_node_t * reportxml_node_get_child_by_attribute(reportxml_node_t *node, const char *key, const char *value, int include_definitions);
|
||||
/* This gets a child by it's type. Otherwise identical to reportxml_node_get_child_by_attribute() */
|
||||
reportxml_node_t * reportxml_node_get_child_by_type(reportxml_node_t *node, reportxml_node_type_t type, int include_definitions);
|
||||
/* This gets and sets the text content of an node (used for <text>) */
|
||||
int reportxml_node_set_content(reportxml_node_t *node, const char *value);
|
||||
char * reportxml_node_get_content(reportxml_node_t *node);
|
||||
|
@ -1063,12 +1063,16 @@ xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, client_t *clien
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr node;
|
||||
xmlNodePtr modules;
|
||||
source_t * source;
|
||||
|
||||
doc = xmlNewDoc (XMLSTR("1.0"));
|
||||
node = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL);
|
||||
xmlDocSetRootElement(doc, node);
|
||||
|
||||
modules = module_container_get_modulelist_as_xml(global.modulecontainer);
|
||||
xmlAddChild(node, modules);
|
||||
|
||||
node = _dump_stats_to_doc(node, show_mount, show_hidden, client);
|
||||
|
||||
if (show_mount && node) {
|
||||
|
Loading…
Reference in New Issue
Block a user