mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-11-03 04:17:17 -05:00
Feature: Support listing listen socket on web interface
This commit is contained in:
parent
80972517da
commit
567b51420f
@ -17,6 +17,7 @@ nobase_dist_admin_DATA = \
|
||||
dashboard.xsl \
|
||||
fallbacks.xsl \
|
||||
showlog.xsl \
|
||||
listensocketlist.xsl \
|
||||
includes/confirm.xsl \
|
||||
includes/footer.xsl \
|
||||
includes/head.xsl \
|
||||
|
@ -11,6 +11,7 @@
|
||||
<li class="adminlink"><a href="/admin/dashboard.xsl">Dashboard</a></li>
|
||||
<li class="adminlink"><a href="/admin/stats.xsl">Server status</a></li>
|
||||
<li class="adminlink"><a href="/admin/listmounts.xsl">Mountpoint list</a></li>
|
||||
<li class="adminlink"><a href="/admin/listensocketlist.xsl">Listen Socket list</a></li>
|
||||
<li class="adminlink"><a href="/admin/showlog.xsl">Logfiles</a></li>
|
||||
<xsl:for-each select="(/report/extension/icestats | /icestats | /iceresponse)/modules/module">
|
||||
<xsl:if test="@management-url and @management-title">
|
||||
|
94
admin/listensocketlist.xsl
Normal file
94
admin/listensocketlist.xsl
Normal file
@ -0,0 +1,94 @@
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
<xsl:include href="includes/page.xsl"/>
|
||||
<xsl:include href="includes/authlist.xsl"/>
|
||||
<xsl:variable name="title">Listen Sockets</xsl:variable>
|
||||
|
||||
<xsl:template name="content">
|
||||
<h2><xsl:value-of select="$title" /></h2>
|
||||
<xsl:for-each select="/report/incident">
|
||||
<section class="box">
|
||||
<h3 class="box_title">Listen Socket <code><xsl:value-of select="resource/value[@member='id']/@value" /></code></h3>
|
||||
<h4>Overview</h4>
|
||||
<table class="table-block">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<xsl:if test="resource/value[@member='id']/@state = 'set'">
|
||||
<tr>
|
||||
<td>ID</td>
|
||||
<td><xsl:value-of select="resource/value[@member='id']/@value" /></td>
|
||||
</tr>
|
||||
</xsl:if>
|
||||
<xsl:if test="resource/value[@member='on_behalf_of']/@state = 'set'">
|
||||
<tr>
|
||||
<td>On behalf of</td>
|
||||
<td><xsl:value-of select="resource/value[@member='on_behalf_of']/@value" /></td>
|
||||
</tr>
|
||||
</xsl:if>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td><xsl:value-of select="resource/value[@member='type']/@value" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Family</td>
|
||||
<td><xsl:value-of select="resource/value[@member='family']/@value" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>Config</h4>
|
||||
<table class="table-block">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<xsl:for-each select="resource/value[@member='config']/value">
|
||||
<xsl:if test="@state != 'unset'">
|
||||
<tr>
|
||||
<td><xsl:value-of select="@member" /></td>
|
||||
<td><xsl:value-of select="@value" /></td>
|
||||
</tr>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<xsl:if test="resource/value[@member='headers']/value">
|
||||
<h4>Header</h4>
|
||||
<table class="table-block">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Name</th>
|
||||
<th>Value</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<xsl:for-each select="resource/value[@member='headers']/value">
|
||||
<tr>
|
||||
<td><xsl:value-of select="value[@member='type']/@value" /></td>
|
||||
<td><xsl:value-of select="value[@member='name']/@value" /></td>
|
||||
<td><xsl:value-of select="value[@member='value']/@value" /></td>
|
||||
<td><xsl:value-of select="value[@member='status']/@value" /></td>
|
||||
</tr>
|
||||
</xsl:for-each>
|
||||
</tbody>
|
||||
</table>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:for-each select="resource/extension/icestats">
|
||||
<h4>Authentication</h4>
|
||||
<xsl:call-template name="authlist" />
|
||||
</xsl:for-each>
|
||||
</section>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
126
src/admin.c
126
src/admin.c
@ -28,10 +28,13 @@
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include "common/net/sock.h"
|
||||
|
||||
#include "admin.h"
|
||||
#include "compat.h"
|
||||
#include "cfgfile.h"
|
||||
#include "connection.h"
|
||||
#include "listensocket.h"
|
||||
#include "refbuf.h"
|
||||
#include "client.h"
|
||||
#include "source.h"
|
||||
@ -95,6 +98,8 @@
|
||||
#define STREAMLIST_HTML_REQUEST "streamlist.xsl"
|
||||
#define STREAMLIST_JSON_REQUEST "streamlist.json"
|
||||
#define STREAMLIST_PLAINTEXT_REQUEST "streamlist.txt"
|
||||
#define LISTENSOCKETLIST_RAW_REQUEST "listensocketlist"
|
||||
#define LISTENSOCKETLIST_HTML_REQUEST "listensocketlist.xsl"
|
||||
#define MOVECLIENTS_RAW_REQUEST "moveclients"
|
||||
#define MOVECLIENTS_HTML_REQUEST "moveclients.xsl"
|
||||
#define MOVECLIENTS_JSON_REQUEST "moveclients.json"
|
||||
@ -145,6 +150,7 @@ static void command_stats (client_t *client, source_t *source, adm
|
||||
static void command_public_stats (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_queue_reload (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_list_mounts (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_list_listen_sockets (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_move_clients (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_kill_client (client_t *client, source_t *source, admin_format_t response);
|
||||
static void command_kill_source (client_t *client, source_t *source, admin_format_t response);
|
||||
@ -183,6 +189,8 @@ static const admin_command_handler_t handlers[] = {
|
||||
{ STREAMLIST_PLAINTEXT_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_PLAINTEXT, ADMINSAFE_SAFE, command_list_mounts, NULL},
|
||||
{ STREAMLIST_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, ADMINSAFE_SAFE, command_list_mounts, NULL},
|
||||
{ STREAMLIST_JSON_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_JSON, ADMINSAFE_SAFE, command_list_mounts, NULL},
|
||||
{ LISTENSOCKETLIST_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, ADMINSAFE_SAFE, command_list_listen_sockets, NULL},
|
||||
{ LISTENSOCKETLIST_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, ADMINSAFE_SAFE, command_list_listen_sockets, NULL},
|
||||
{ MOVECLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_RAW, ADMINSAFE_HYBRID, command_move_clients, NULL},
|
||||
{ MOVECLIENTS_HTML_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, ADMINSAFE_HYBRID, command_move_clients, NULL},
|
||||
{ MOVECLIENTS_JSON_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_JSON, ADMINSAFE_HYBRID, command_move_clients, NULL},
|
||||
@ -1311,6 +1319,124 @@ static void command_list_mounts(client_t *client, source_t *source, admin_format
|
||||
}
|
||||
}
|
||||
|
||||
static void command_list_listen_sockets(client_t *client, source_t *source, admin_format_t response)
|
||||
{
|
||||
reportxml_t *report = client_get_empty_reportxml();
|
||||
listensocket_t ** sockets;
|
||||
size_t i;
|
||||
|
||||
global_lock();
|
||||
sockets = listensocket_container_list_sockets(global.listensockets);
|
||||
global_unlock();
|
||||
|
||||
for (i = 0; sockets[i]; i++) {
|
||||
const listener_t * listener = listensocket_get_listener(sockets[i]);
|
||||
reportxml_node_t * incident = client_add_empty_incident(report, "ee231290-81c6-484a-836c-20a00ad09898", NULL, NULL);
|
||||
reportxml_node_t * resource = reportxml_node_new(REPORTXML_NODE_TYPE_RESOURCE, NULL, NULL, NULL);
|
||||
reportxml_node_t * config = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
|
||||
|
||||
reportxml_node_set_attribute(resource, "type", "result");
|
||||
reportxml_node_set_attribute(config, "type", "structure");
|
||||
reportxml_node_set_attribute(config, "member", "config");
|
||||
|
||||
reportxml_node_add_child(resource, config);
|
||||
reportxml_node_add_child(incident, resource);
|
||||
refobject_unref(incident);
|
||||
|
||||
reportxml_helper_add_value_enum(resource, "type", listensocket_type_to_string(listener->type));
|
||||
reportxml_helper_add_value_enum(resource, "family", sock_family_to_string(listensocket_get_family(sockets[i])));
|
||||
reportxml_helper_add_value_string(resource, "id", listener->id);
|
||||
reportxml_helper_add_value_string(resource, "on_behalf_of", listener->on_behalf_of);
|
||||
|
||||
if (listener->port > 0) {
|
||||
reportxml_helper_add_value_int(config, "port", listener->port);
|
||||
} else {
|
||||
reportxml_helper_add_value(config, "int", "port", NULL);
|
||||
}
|
||||
|
||||
if (listener->so_sndbuf) {
|
||||
reportxml_helper_add_value_int(config, "so_sndbuf", listener->so_sndbuf);
|
||||
} else {
|
||||
reportxml_helper_add_value(config, "int", "so_sndbuf", NULL);
|
||||
}
|
||||
|
||||
if (listener->listen_backlog > 0) {
|
||||
reportxml_helper_add_value_int(config, "listen_backlog", listener->listen_backlog);
|
||||
} else {
|
||||
reportxml_helper_add_value(config, "int", "listen_backlog", NULL);
|
||||
}
|
||||
|
||||
reportxml_helper_add_value_string(config, "bind_address", listener->bind_address);
|
||||
reportxml_helper_add_value_boolean(config, "shoutcast_compat", listener->shoutcast_compat);
|
||||
reportxml_helper_add_value_string(config, "shoutcast_mount", listener->shoutcast_mount);
|
||||
reportxml_helper_add_value_enum(config, "tlsmode", listensocket_tlsmode_to_string(listener->tls));
|
||||
|
||||
if (listener->authstack) {
|
||||
reportxml_node_t * extension = reportxml_node_new(REPORTXML_NODE_TYPE_EXTENSION, NULL, NULL, NULL);
|
||||
xmlNodePtr xmlroot = xmlNewNode(NULL, XMLSTR("icestats"));
|
||||
|
||||
reportxml_node_set_attribute(extension, "application", ADMIN_ICESTATS_LEGACY_EXTENSION_APPLICATION);
|
||||
reportxml_node_add_child(resource, extension);
|
||||
|
||||
xmlSetProp(xmlroot, XMLSTR("xmlns"), XMLSTR(XMLNS_LEGACY_STATS));
|
||||
|
||||
stats_add_authstack(listener->authstack, xmlroot);
|
||||
|
||||
reportxml_node_add_xml_child(extension, xmlroot);
|
||||
refobject_unref(extension);
|
||||
xmlFreeNode(xmlroot);
|
||||
}
|
||||
|
||||
if (listener->http_headers) {
|
||||
reportxml_node_t * headers = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
|
||||
ice_config_http_header_t *cur;
|
||||
|
||||
reportxml_node_set_attribute(headers, "member", "headers");
|
||||
reportxml_node_set_attribute(headers, "type", "unordered-list");
|
||||
reportxml_node_add_child(resource, headers);
|
||||
|
||||
for (cur = listener->http_headers; cur; cur = cur->next) {
|
||||
reportxml_node_t * header = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
|
||||
reportxml_node_set_attribute(header, "type", "structure");
|
||||
reportxml_node_add_child(headers, header);
|
||||
|
||||
switch (cur->type) {
|
||||
case HTTP_HEADER_TYPE_STATIC:
|
||||
reportxml_helper_add_value_enum(header, "type", "static");
|
||||
break;
|
||||
case HTTP_HEADER_TYPE_CORS:
|
||||
reportxml_helper_add_value_enum(header, "type", "cors");
|
||||
break;
|
||||
}
|
||||
|
||||
reportxml_helper_add_value_string(header, "name", cur->name);
|
||||
reportxml_helper_add_value_string(header, "value", cur->value);
|
||||
|
||||
if (cur->status > 100) {
|
||||
reportxml_helper_add_value_int(header, "status", cur->status > 100);
|
||||
} else {
|
||||
reportxml_helper_add_value(header, "int", "status", NULL);
|
||||
}
|
||||
|
||||
reportxml_helper_add_value_string(config, "shoutcast_mount", listener->shoutcast_mount);
|
||||
refobject_unref(header);
|
||||
}
|
||||
|
||||
refobject_unref(headers);
|
||||
}
|
||||
|
||||
refobject_unref(config);
|
||||
refobject_unref(resource);
|
||||
listensocket_release_listener(sockets[i]);
|
||||
refobject_unref(sockets[i]);
|
||||
}
|
||||
|
||||
free(sockets);
|
||||
|
||||
client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, LISTENSOCKETLIST_HTML_REQUEST, response, 200, NULL);
|
||||
refobject_unref(report);
|
||||
}
|
||||
|
||||
static void command_updatemetadata(client_t *client,
|
||||
source_t *source,
|
||||
admin_format_t response)
|
||||
|
@ -506,6 +506,30 @@ listensocket_t * listensocket_container_get_by_id(listensocket_container_t *self
|
||||
return NULL;
|
||||
}
|
||||
|
||||
listensocket_t ** listensocket_container_list_sockets(listensocket_container_t *self)
|
||||
{
|
||||
listensocket_t **res;
|
||||
size_t idx = 0;
|
||||
size_t i;
|
||||
|
||||
thread_mutex_lock(&self->lock);
|
||||
res = calloc(self->sock_len + 1, sizeof(*res));
|
||||
if (!res) {
|
||||
thread_mutex_unlock(&self->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < self->sock_len; i++) {
|
||||
if (self->sock[i] != NULL) {
|
||||
refobject_ref(res[idx++] = self->sock[i]);
|
||||
}
|
||||
}
|
||||
|
||||
thread_mutex_unlock(&self->lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
static void __listensocket_free(refobject_t self, void **userdata)
|
||||
|
@ -25,6 +25,7 @@ connection_t * listensocket_container_accept(listensocket_container
|
||||
int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata);
|
||||
ssize_t listensocket_container_sockcount(listensocket_container_t *self);
|
||||
listensocket_t * listensocket_container_get_by_id(listensocket_container_t *self, const char *id);
|
||||
listensocket_t ** listensocket_container_list_sockets(listensocket_container_t *self);
|
||||
|
||||
REFOBJECT_FORWARD_TYPE(listensocket_t);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user