1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-06-02 06:01:10 +00:00

Feature: Support listing listen socket on web interface

This commit is contained in:
Philipp Schafft 2022-03-06 18:29:30 +00:00
parent 80972517da
commit 567b51420f
6 changed files with 247 additions and 0 deletions

View File

@ -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 \

View File

@ -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">

View 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>

View File

@ -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)

View File

@ -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)

View File

@ -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);