mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-09-29 04:25:55 -04:00
Merge branch 'feature-source-health' into devel
This commit is contained in:
commit
0287d49978
@ -16,10 +16,24 @@
|
|||||||
<section class="box">
|
<section class="box">
|
||||||
<h3 class="box_title">Mountpoint <code><xsl:value-of select="@mount" /></code></h3>
|
<h3 class="box_title">Mountpoint <code><xsl:value-of select="@mount" /></code></h3>
|
||||||
<!-- Mount nav -->
|
<!-- Mount nav -->
|
||||||
<xsl:call-template name="mountnav" />
|
<div class="side-by-side">
|
||||||
|
<div class="trafficlight colour-{health/text()}"> </div>
|
||||||
|
<xsl:call-template name="mountnav" />
|
||||||
|
</div>
|
||||||
<xsl:call-template name="player" />
|
<xsl:call-template name="player" />
|
||||||
<p><xsl:value-of select="listeners" /> Listener(s)</p>
|
<p><xsl:value-of select="listeners" /> Listener(s)</p>
|
||||||
|
|
||||||
|
<xsl:if test="maintenance/*">
|
||||||
|
<h4>Maintenance</h4>
|
||||||
|
<ul class="maintenance-container">
|
||||||
|
<xsl:for-each select="maintenance/*">
|
||||||
|
<li class="maintenance-level-{@maintenance-level}">
|
||||||
|
<p><xsl:value-of select="text()" /></p>
|
||||||
|
</li>
|
||||||
|
</xsl:for-each>
|
||||||
|
</ul>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
<!-- Mount Authentication -->
|
<!-- Mount Authentication -->
|
||||||
<xsl:if test="authentication">
|
<xsl:if test="authentication">
|
||||||
<h4>Mount Authentication</h4>
|
<h4>Mount Authentication</h4>
|
||||||
|
97
src/admin.c
97
src/admin.c
@ -167,12 +167,6 @@
|
|||||||
#define DEFAULT_HTML_REQUEST ""
|
#define DEFAULT_HTML_REQUEST ""
|
||||||
#define BUILDM3U_RAW_REQUEST "buildm3u"
|
#define BUILDM3U_RAW_REQUEST "buildm3u"
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ADMIN_DASHBOARD_STATUS_OK = 0,
|
|
||||||
ADMIN_DASHBOARD_STATUS_WARNING = 1,
|
|
||||||
ADMIN_DASHBOARD_STATUS_ERROR = 2
|
|
||||||
} admin_dashboard_status_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
size_t length;
|
size_t length;
|
||||||
@ -476,6 +470,33 @@ xmlNodePtr admin_build_rootnode(xmlDocPtr doc, const char *name)
|
|||||||
return rootnode;
|
return rootnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void admin_build_sourcelist__add_flag(xmlNodePtr parent, source_flags_t flags, source_flags_t flag, bool invert, const char *name, const char *description)
|
||||||
|
{
|
||||||
|
xmlNodePtr node;
|
||||||
|
source_flags_t testflags = SOURCE_FLAGS_GOOD|flag;
|
||||||
|
|
||||||
|
if (invert ? (flags & flag) : !(flags & flag))
|
||||||
|
return;
|
||||||
|
|
||||||
|
node = xmlNewTextChild(parent, NULL, XMLSTR("flag"), XMLSTR(description));
|
||||||
|
xmlSetProp(node, XMLSTR("value"), XMLSTR(name));
|
||||||
|
|
||||||
|
if (invert)
|
||||||
|
testflags &= ~flag;
|
||||||
|
|
||||||
|
switch (source_get_health_by_flags(testflags)) {
|
||||||
|
case HEALTH_OK:
|
||||||
|
xmlSetProp(node, XMLSTR("maintenance-level"), XMLSTR("info"));
|
||||||
|
break;
|
||||||
|
case HEALTH_WARNING:
|
||||||
|
xmlSetProp(node, XMLSTR("maintenance-level"), XMLSTR("warning"));
|
||||||
|
break;
|
||||||
|
case HEALTH_ERROR:
|
||||||
|
xmlSetProp(node, XMLSTR("maintenance-level"), XMLSTR("error"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* build an XML doc containing information about currently running sources.
|
/* 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
|
* If a mountpoint is passed then that source will not be added to the XML
|
||||||
* doc even if the source is running */
|
* doc even if the source is running */
|
||||||
@ -536,6 +557,9 @@ xmlDocPtr admin_build_sourcelist(const char *mount, client_t *client, admin_form
|
|||||||
config_release_config();
|
config_release_config();
|
||||||
|
|
||||||
if (source->running) {
|
if (source->running) {
|
||||||
|
const source_flags_t flags = source->flags;
|
||||||
|
xmlNodePtr maintenancenode;
|
||||||
|
|
||||||
if (source->client) {
|
if (source->client) {
|
||||||
snprintf(buf, sizeof(buf), "%lu",
|
snprintf(buf, sizeof(buf), "%lu",
|
||||||
(unsigned long)(now - source->con->con_time));
|
(unsigned long)(now - source->con->con_time));
|
||||||
@ -547,6 +571,25 @@ xmlDocPtr admin_build_sourcelist(const char *mount, client_t *client, admin_form
|
|||||||
}
|
}
|
||||||
xmlNewTextChild(srcnode, NULL, XMLSTR("content-type"),
|
xmlNewTextChild(srcnode, NULL, XMLSTR("content-type"),
|
||||||
XMLSTR(source->format->contenttype));
|
XMLSTR(source->format->contenttype));
|
||||||
|
|
||||||
|
switch (source_get_health(source)) {
|
||||||
|
case HEALTH_OK:
|
||||||
|
xmlNewTextChild(srcnode, NULL, XMLSTR("health"), XMLSTR("green"));
|
||||||
|
break;
|
||||||
|
case HEALTH_WARNING:
|
||||||
|
xmlNewTextChild(srcnode, NULL, XMLSTR("health"), XMLSTR("yellow"));
|
||||||
|
break;
|
||||||
|
case HEALTH_ERROR:
|
||||||
|
xmlNewTextChild(srcnode, NULL, XMLSTR("health"), XMLSTR("red"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
maintenancenode = xmlNewChild(srcnode, NULL, XMLSTR("maintenance"), NULL);
|
||||||
|
xmlSetProp(maintenancenode, XMLSTR("comment"), XMLSTR("This is an experimental node. Do not use!"));
|
||||||
|
|
||||||
|
admin_build_sourcelist__add_flag(maintenancenode, flags, SOURCE_FLAG_GOT_DATA, true, "no-got-data", "No data has yet been received.");
|
||||||
|
admin_build_sourcelist__add_flag(maintenancenode, flags, SOURCE_FLAG_FORMAT_GENERIC, false, "format-generic", "Legacy or unsupported streaming format is used.");
|
||||||
|
admin_build_sourcelist__add_flag(maintenancenode, flags, SOURCE_FLAG_LEGACY_METADATA, false, "legacy-metadata", "Legacy metadata on non-legacy source received. This is likely a bug in the source client.");
|
||||||
|
admin_build_sourcelist__add_flag(maintenancenode, flags, SOURCE_FLAG_AGED, true, "no-aged", "The stream did not mature yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%"PRIu64, source->dumpfile_written);
|
snprintf(buf, sizeof(buf), "%"PRIu64, source->dumpfile_written);
|
||||||
@ -1212,6 +1255,7 @@ static void command_metadata(client_t *client,
|
|||||||
if (source->parser && source->parser->req_type == httpp_req_put) {
|
if (source->parser && source->parser->req_type == httpp_req_put) {
|
||||||
ICECAST_LOG_ERROR("Got legacy SOURCE-style metadata update command on "
|
ICECAST_LOG_ERROR("Got legacy SOURCE-style metadata update command on "
|
||||||
"source connected with PUT at mountpoint %H", source->mount);
|
"source connected with PUT at mountpoint %H", source->mount);
|
||||||
|
source_set_flags(source, SOURCE_FLAG_LEGACY_METADATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_REQUIRE(client, "mode", action);
|
COMMAND_REQUIRE(client, "mode", action);
|
||||||
@ -1256,6 +1300,7 @@ static void command_metadata(client_t *client,
|
|||||||
} else {
|
} else {
|
||||||
ICECAST_LOG_ERROR("Got legacy shoutcast-style metadata update command "
|
ICECAST_LOG_ERROR("Got legacy shoutcast-style metadata update command "
|
||||||
"on source that does not accept it at mountpoint %H", source->mount);
|
"on source that does not accept it at mountpoint %H", source->mount);
|
||||||
|
source_set_flags(source, SOURCE_FLAG_LEGACY_METADATA);
|
||||||
|
|
||||||
admin_send_response_simple(client, source, response, "Mountpoint will not accept URL updates", 1);
|
admin_send_response_simple(client, source, response, "Mountpoint will not accept URL updates", 1);
|
||||||
return;
|
return;
|
||||||
@ -1629,19 +1674,10 @@ static void __reportxml_add_maintenance(reportxml_node_t *parent, reportxml_data
|
|||||||
refobject_unref(incident);
|
refobject_unref(incident);
|
||||||
}
|
}
|
||||||
|
|
||||||
static admin_dashboard_status_t command_dashboard__atbest(admin_dashboard_status_t a, admin_dashboard_status_t b)
|
|
||||||
{
|
|
||||||
if (a > b) {
|
|
||||||
return a;
|
|
||||||
} else {
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_GETRLIMIT && HAVE_SYS_RESOURCE_H
|
#if HAVE_GETRLIMIT && HAVE_SYS_RESOURCE_H
|
||||||
static admin_dashboard_status_t command_dashboard__getrlimit(ice_config_t *config, reportxml_node_t *parent, reportxml_database_t *db)
|
static health_t command_dashboard__getrlimit(ice_config_t *config, reportxml_node_t *parent, reportxml_database_t *db)
|
||||||
{
|
{
|
||||||
admin_dashboard_status_t ret = ADMIN_DASHBOARD_STATUS_OK;
|
health_t ret = HEALTH_OK;
|
||||||
struct rlimit limit;
|
struct rlimit limit;
|
||||||
|
|
||||||
if (getrlimit(RLIMIT_NOFILE, &limit) == 0) {
|
if (getrlimit(RLIMIT_NOFILE, &limit) == 0) {
|
||||||
@ -1651,7 +1687,7 @@ static admin_dashboard_status_t command_dashboard__getrlimit(ice_config_t *confi
|
|||||||
// We assume that we need one FD per client, at max three per source (e.g. for auth), and at max 24 additional for logfiles and similar.
|
// We assume that we need one FD per client, at max three per source (e.g. for auth), and at max 24 additional for logfiles and similar.
|
||||||
// This is just an estimation.
|
// This is just an estimation.
|
||||||
__reportxml_add_maintenance(parent, db, "a93a842a-9664-43a9-b707-7f358066fe2b", "error", "Global client, and source limit is bigger than suitable for current open file limit.", NULL);
|
__reportxml_add_maintenance(parent, db, "a93a842a-9664-43a9-b707-7f358066fe2b", "error", "Global client, and source limit is bigger than suitable for current open file limit.", NULL);
|
||||||
ret = command_dashboard__atbest(ret, ADMIN_DASHBOARD_STATUS_ERROR);
|
ret = health_atbest(ret, HEALTH_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1674,7 +1710,7 @@ static void command_dashboard (client_t *client, source_t *source, adm
|
|||||||
reportxml_t *report = client_get_reportxml("0aa76ea1-bf42-49d1-887e-ca95fb307dc4", NULL, NULL);
|
reportxml_t *report = client_get_reportxml("0aa76ea1-bf42-49d1-887e-ca95fb307dc4", NULL, NULL);
|
||||||
reportxml_node_t *reportnode = reportxml_get_node_by_type(report, REPORTXML_NODE_TYPE_REPORT, 0);
|
reportxml_node_t *reportnode = reportxml_get_node_by_type(report, REPORTXML_NODE_TYPE_REPORT, 0);
|
||||||
reportxml_node_t *incident = reportxml_get_node_by_type(report, REPORTXML_NODE_TYPE_INCIDENT, 0);
|
reportxml_node_t *incident = reportxml_get_node_by_type(report, REPORTXML_NODE_TYPE_INCIDENT, 0);
|
||||||
admin_dashboard_status_t status = ADMIN_DASHBOARD_STATUS_OK;
|
health_t health = HEALTH_OK;
|
||||||
reportxml_node_t *resource;
|
reportxml_node_t *resource;
|
||||||
reportxml_node_t *node;
|
reportxml_node_t *node;
|
||||||
bool has_sources;
|
bool has_sources;
|
||||||
@ -1713,13 +1749,13 @@ static void command_dashboard (client_t *client, source_t *source, adm
|
|||||||
refobject_unref(node);
|
refobject_unref(node);
|
||||||
|
|
||||||
if (config->config_problems || has_too_many_clients || !inet6_enabled) {
|
if (config->config_problems || has_too_many_clients || !inet6_enabled) {
|
||||||
status = command_dashboard__atbest(status, ADMIN_DASHBOARD_STATUS_ERROR);
|
health = health_atbest(health, HEALTH_ERROR);
|
||||||
} else if (!has_sources || has_many_clients) {
|
} else if (!has_sources || has_many_clients) {
|
||||||
status = command_dashboard__atbest(status, ADMIN_DASHBOARD_STATUS_WARNING);
|
health = health_atbest(health, HEALTH_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEVEL_LOGGING
|
#ifdef DEVEL_LOGGING
|
||||||
status = command_dashboard__atbest(status, ADMIN_DASHBOARD_STATUS_WARNING);
|
health = health_atbest(health, HEALTH_WARNING);
|
||||||
__reportxml_add_maintenance(reportnode, config->reportxml_db, "c704804e-d3b9-4544-898b-d477078135de", "warning", "Developer logging is active. This mode is not for production.", NULL);
|
__reportxml_add_maintenance(reportnode, config->reportxml_db, "c704804e-d3b9-4544-898b-d477078135de", "warning", "Developer logging is active. This mode is not for production.", NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1760,20 +1796,13 @@ static void command_dashboard (client_t *client, source_t *source, adm
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_GETRLIMIT && HAVE_SYS_RESOURCE_H
|
#if HAVE_GETRLIMIT && HAVE_SYS_RESOURCE_H
|
||||||
status = command_dashboard__atbest(status, command_dashboard__getrlimit(config, reportnode, config->reportxml_db));
|
if (true) {
|
||||||
|
health_t limits = command_dashboard__getrlimit(config, reportnode, config->reportxml_db);
|
||||||
|
health = health_atbest(health, limits);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (status) {
|
reportxml_helper_add_value_health(resource, "status", health);
|
||||||
case ADMIN_DASHBOARD_STATUS_OK:
|
|
||||||
reportxml_helper_add_value_enum(resource, "status", "green");
|
|
||||||
break;
|
|
||||||
case ADMIN_DASHBOARD_STATUS_WARNING:
|
|
||||||
reportxml_helper_add_value_enum(resource, "status", "yellow");
|
|
||||||
break;
|
|
||||||
case ADMIN_DASHBOARD_STATUS_ERROR:
|
|
||||||
reportxml_helper_add_value_enum(resource, "status", "red");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
reportxml_node_add_child(incident, resource);
|
reportxml_node_add_child(incident, resource);
|
||||||
refobject_unref(resource);
|
refobject_unref(resource);
|
||||||
|
@ -952,6 +952,9 @@ int connection_complete_source(source_t *source, int response)
|
|||||||
format_type = FORMAT_TYPE_GENERIC;
|
format_type = FORMAT_TYPE_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (format_type == FORMAT_TYPE_GENERIC)
|
||||||
|
source_set_flags(source, SOURCE_FLAG_FORMAT_GENERIC);
|
||||||
|
|
||||||
if (format_get_plugin (format_type, source) < 0) {
|
if (format_get_plugin (format_type, source) < 0) {
|
||||||
global_unlock();
|
global_unlock();
|
||||||
config_release_config();
|
config_release_config();
|
||||||
|
@ -22,6 +22,14 @@
|
|||||||
#define XMLNS_LEGACY_STATS "http://icecast.org/specs/legacystats-0.0.1"
|
#define XMLNS_LEGACY_STATS "http://icecast.org/specs/legacystats-0.0.1"
|
||||||
#define XMLNS_LEGACY_RESPONSE "http://icecast.org/specs/legacyresponse-0.0.1"
|
#define XMLNS_LEGACY_RESPONSE "http://icecast.org/specs/legacyresponse-0.0.1"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HEALTH_OK = 0,
|
||||||
|
HEALTH_WARNING = 1,
|
||||||
|
HEALTH_ERROR = 2
|
||||||
|
} health_t;
|
||||||
|
|
||||||
|
#define health_atbest(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
/* ---[ client.[ch] ]--- */
|
/* ---[ client.[ch] ]--- */
|
||||||
|
|
||||||
typedef struct _client_tag client_t;
|
typedef struct _client_tag client_t;
|
||||||
|
@ -43,6 +43,21 @@ void reportxml_helper_add_value_int(reportxml_node_t *parent, const char *member
|
|||||||
reportxml_helper_add_value(parent, "int", member, buf);
|
reportxml_helper_add_value(parent, "int", member, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reportxml_helper_add_value_health(reportxml_node_t *parent, const char *member, health_t val)
|
||||||
|
{
|
||||||
|
switch (val) {
|
||||||
|
case HEALTH_OK:
|
||||||
|
reportxml_helper_add_value_enum(parent, member, "green");
|
||||||
|
break;
|
||||||
|
case HEALTH_WARNING:
|
||||||
|
reportxml_helper_add_value_enum(parent, member, "yellow");
|
||||||
|
break;
|
||||||
|
case HEALTH_ERROR:
|
||||||
|
reportxml_helper_add_value_enum(parent, member, "red");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void reportxml_helper_add_text(reportxml_node_t *parent, const char *definition, const char *text)
|
void reportxml_helper_add_text(reportxml_node_t *parent, const char *definition, const char *text)
|
||||||
{
|
{
|
||||||
reportxml_node_t *textnode = reportxml_node_new(REPORTXML_NODE_TYPE_TEXT, NULL, definition, NULL);
|
reportxml_node_t *textnode = reportxml_node_new(REPORTXML_NODE_TYPE_TEXT, NULL, definition, NULL);
|
||||||
|
@ -20,6 +20,7 @@ void reportxml_helper_add_value(reportxml_node_t *parent, const char *type, cons
|
|||||||
#define reportxml_helper_add_value_boolean(parent,member,value) reportxml_helper_add_value((parent), "boolean", (member), (value) ? "true" : "false")
|
#define reportxml_helper_add_value_boolean(parent,member,value) reportxml_helper_add_value((parent), "boolean", (member), (value) ? "true" : "false")
|
||||||
#define reportxml_helper_add_value_flag(parent,member,value) reportxml_helper_add_value((parent), "flag", (member), (value) ? "true" : "false")
|
#define reportxml_helper_add_value_flag(parent,member,value) reportxml_helper_add_value((parent), "flag", (member), (value) ? "true" : "false")
|
||||||
void reportxml_helper_add_value_int(reportxml_node_t *parent, const char *member, long long int val);
|
void reportxml_helper_add_value_int(reportxml_node_t *parent, const char *member, long long int val);
|
||||||
|
void reportxml_helper_add_value_health(reportxml_node_t *parent, const char *member, health_t val);
|
||||||
|
|
||||||
void reportxml_helper_add_text(reportxml_node_t *parent, const char *definition, const char *text);
|
void reportxml_helper_add_text(reportxml_node_t *parent, const char *definition, const char *text);
|
||||||
|
|
||||||
|
55
src/source.c
55
src/source.c
@ -290,6 +290,8 @@ void source_clear_source (source_t *source)
|
|||||||
source->hidden = 0;
|
source->hidden = 0;
|
||||||
source->shoutcast_compat = 0;
|
source->shoutcast_compat = 0;
|
||||||
source->last_stats_update = 0;
|
source->last_stats_update = 0;
|
||||||
|
source->create_time = 0;
|
||||||
|
source->flags = 0;
|
||||||
util_dict_free(source->audio_info);
|
util_dict_free(source->audio_info);
|
||||||
source->audio_info = NULL;
|
source->audio_info = NULL;
|
||||||
|
|
||||||
@ -500,12 +502,18 @@ static refbuf_t *get_next_buffer (source_t *source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (current >= (source->last_stats_update + 5)) {
|
if (current >= (source->last_stats_update + 5)) {
|
||||||
|
time_t age = current - source->create_time;
|
||||||
|
|
||||||
stats_event_args(source->mount, "total_bytes_read", "%"PRIu64, source->format->read_bytes);
|
stats_event_args(source->mount, "total_bytes_read", "%"PRIu64, source->format->read_bytes);
|
||||||
stats_event_args(source->mount, "total_bytes_sent", "%"PRIu64, source->format->sent_bytes);
|
stats_event_args(source->mount, "total_bytes_sent", "%"PRIu64, source->format->sent_bytes);
|
||||||
if (source->dumpfile) {
|
if (source->dumpfile) {
|
||||||
stats_event_args(source->mount, "dumpfile_written", "%"PRIu64, source->dumpfile_written);
|
stats_event_args(source->mount, "dumpfile_written", "%"PRIu64, source->dumpfile_written);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (age > 30) { /* TODO: Should this be configurable? */
|
||||||
|
source_set_flags(source, SOURCE_FLAG_AGED);
|
||||||
|
}
|
||||||
|
|
||||||
source->last_stats_update = current;
|
source->last_stats_update = current;
|
||||||
}
|
}
|
||||||
if (fds < 0) {
|
if (fds < 0) {
|
||||||
@ -537,6 +545,9 @@ static refbuf_t *get_next_buffer (source_t *source)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (refbuf)
|
||||||
|
source_set_flags(source, SOURCE_FLAG_GOT_DATA);
|
||||||
|
|
||||||
return refbuf;
|
return refbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,6 +648,7 @@ static void source_init (source_t *source)
|
|||||||
{
|
{
|
||||||
char listenurl[512];
|
char listenurl[512];
|
||||||
const char *str;
|
const char *str;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
str = httpp_getvar(source->parser, "ice-audio-info");
|
str = httpp_getvar(source->parser, "ice-audio-info");
|
||||||
source->audio_info = util_dict_new();
|
source->audio_info = util_dict_new();
|
||||||
@ -664,8 +676,11 @@ static void source_init (source_t *source)
|
|||||||
stats_event_time (source->mount, "stream_start");
|
stats_event_time (source->mount, "stream_start");
|
||||||
stats_event_time_iso8601 (source->mount, "stream_start_iso8601");
|
stats_event_time_iso8601 (source->mount, "stream_start_iso8601");
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
source->last_read = now;
|
||||||
|
source->create_time = now;
|
||||||
|
|
||||||
ICECAST_LOG_DEBUG("Source creation complete");
|
ICECAST_LOG_DEBUG("Source creation complete");
|
||||||
source->last_read = time (NULL);
|
|
||||||
source->prev_listeners = -1;
|
source->prev_listeners = -1;
|
||||||
source->running = 1;
|
source->running = 1;
|
||||||
|
|
||||||
@ -1013,6 +1028,8 @@ static void source_apply_mount (ice_config_t *config, source_t *source, mount_pr
|
|||||||
avl_tree_rlock (source->client_tree);
|
avl_tree_rlock (source->client_tree);
|
||||||
stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
|
stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
|
||||||
|
|
||||||
|
source->flags &= ~SOURCE_FLAGS_CLEARABLE;
|
||||||
|
|
||||||
if (mountinfo)
|
if (mountinfo)
|
||||||
{
|
{
|
||||||
source->max_listeners = mountinfo->max_listeners;
|
source->max_listeners = mountinfo->max_listeners;
|
||||||
@ -1515,3 +1532,39 @@ void source_kill_dumpfile(source_t *source)
|
|||||||
stats_event(source->mount, "dumpfile_written", NULL);
|
stats_event(source->mount, "dumpfile_written", NULL);
|
||||||
stats_event(source->mount, "dumpfile_start", NULL);
|
stats_event(source->mount, "dumpfile_start", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
health_t source_get_health(source_t *source)
|
||||||
|
{
|
||||||
|
const source_flags_t flags = source->flags;
|
||||||
|
return source_get_health_by_flags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
health_t source_get_health_by_flags(source_flags_t flags)
|
||||||
|
{
|
||||||
|
health_t health = HEALTH_OK;
|
||||||
|
|
||||||
|
if (!(flags & SOURCE_FLAG_GOT_DATA))
|
||||||
|
health = health_atbest(health, HEALTH_ERROR);
|
||||||
|
|
||||||
|
if (flags & SOURCE_FLAG_FORMAT_GENERIC)
|
||||||
|
health = health_atbest(health, HEALTH_WARNING);
|
||||||
|
|
||||||
|
if (flags & SOURCE_FLAG_LEGACY_METADATA)
|
||||||
|
health = health_atbest(health, HEALTH_ERROR);
|
||||||
|
|
||||||
|
if (!(flags & SOURCE_FLAG_AGED))
|
||||||
|
health = health_atbest(health, HEALTH_WARNING);
|
||||||
|
|
||||||
|
return health;
|
||||||
|
}
|
||||||
|
|
||||||
|
void source_set_flags(source_t *source, source_flags_t flags)
|
||||||
|
{
|
||||||
|
/* check if we need to do anything at all */
|
||||||
|
if ((source->flags & flags) == flags)
|
||||||
|
return;
|
||||||
|
|
||||||
|
thread_mutex_lock(&source->lock);
|
||||||
|
source->flags |= flags;
|
||||||
|
thread_mutex_unlock(&source->lock);
|
||||||
|
}
|
||||||
|
16
src/source.h
16
src/source.h
@ -15,6 +15,7 @@
|
|||||||
#define __SOURCE_H__
|
#define __SOURCE_H__
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "common/thread/thread.h"
|
#include "common/thread/thread.h"
|
||||||
@ -27,12 +28,23 @@
|
|||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
|
|
||||||
|
typedef uint_least32_t source_flags_t;
|
||||||
|
|
||||||
|
#define SOURCE_FLAG_GOT_DATA ((source_flags_t)0x00000001U)
|
||||||
|
#define SOURCE_FLAG_FORMAT_GENERIC ((source_flags_t)0x00000002U)
|
||||||
|
#define SOURCE_FLAG_LEGACY_METADATA ((source_flags_t)0x00000004U)
|
||||||
|
#define SOURCE_FLAG_AGED ((source_flags_t)0x00000008U)
|
||||||
|
|
||||||
|
#define SOURCE_FLAGS_CLEARABLE (SOURCE_FLAG_LEGACY_METADATA)
|
||||||
|
#define SOURCE_FLAGS_GOOD (SOURCE_FLAG_GOT_DATA|SOURCE_FLAG_AGED)
|
||||||
|
|
||||||
struct source_tag {
|
struct source_tag {
|
||||||
mutex_t lock;
|
mutex_t lock;
|
||||||
client_t *client;
|
client_t *client;
|
||||||
connection_t *con;
|
connection_t *con;
|
||||||
http_parser_t *parser;
|
http_parser_t *parser;
|
||||||
time_t last_stats_update;
|
time_t last_stats_update;
|
||||||
|
time_t create_time;
|
||||||
|
|
||||||
char *mount; // TODO: Should we at some point migrate away from this to only use identifier?
|
char *mount; // TODO: Should we at some point migrate away from this to only use identifier?
|
||||||
mount_identifier_t *identifier;
|
mount_identifier_t *identifier;
|
||||||
@ -43,6 +55,7 @@ struct source_tag {
|
|||||||
/* set to zero to request the source to shutdown without causing a global
|
/* set to zero to request the source to shutdown without causing a global
|
||||||
* shutdown */
|
* shutdown */
|
||||||
int running;
|
int running;
|
||||||
|
source_flags_t flags;
|
||||||
|
|
||||||
struct _format_plugin_tag *format;
|
struct _format_plugin_tag *format;
|
||||||
|
|
||||||
@ -114,6 +127,9 @@ void source_recheck_mounts (int update_all);
|
|||||||
/* Writes a buffer of raw data to a dumpfile. returns true if the write was successful (and complete). */
|
/* Writes a buffer of raw data to a dumpfile. returns true if the write was successful (and complete). */
|
||||||
bool source_write_dumpfile(source_t *source, const void *buffer, size_t len);
|
bool source_write_dumpfile(source_t *source, const void *buffer, size_t len);
|
||||||
void source_kill_dumpfile(source_t *source);
|
void source_kill_dumpfile(source_t *source);
|
||||||
|
health_t source_get_health(source_t *source);
|
||||||
|
health_t source_get_health_by_flags(source_flags_t flags);
|
||||||
|
void source_set_flags(source_t *source, source_flags_t flags);
|
||||||
|
|
||||||
extern mutex_t move_clients_mutex;
|
extern mutex_t move_clients_mutex;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user