1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-09-29 04:25:55 -04:00

Merge branch 'update-events' into devel

This commit is contained in:
Philipp Schafft 2022-09-17 17:59:30 +00:00
commit b2167151bb
6 changed files with 297 additions and 78 deletions

View File

@ -12,16 +12,23 @@
#endif
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdbool.h>
#include <igloo/error.h>
#include <igloo/sp.h>
#include "event.h"
#include "fastevent.h"
#include "logging.h"
#include "string_renderer.h"
#include "admin.h"
#include "connection.h"
#include "client.h"
#include "source.h"
#include "cfgfile.h"
#include "global.h" /* for igloo_instance */
#define CATMODULE "event"
@ -31,6 +38,87 @@ static bool event_running = false;
static thread_type *event_thread = NULL;
static cond_t cond;
/* ignores errors */
static void extra_add(event_t *event, event_extra_key_t key, const char *value)
{
if (!value)
return;
if (event->extra_fill == event->extra_size) {
event_extra_entry_t *n = realloc(event->extra_entries, sizeof(*n)*(event->extra_size + 16));
if (!n)
return;
memset(&(n[event->extra_size]), 0, sizeof(*n)*16);
event->extra_size += 16;
event->extra_entries = n;
}
if (igloo_sp_replace(value, &(event->extra_entries[event->extra_fill].value), igloo_instance) == igloo_ERROR_NONE) {
event->extra_entries[event->extra_fill].key = key;
event->extra_fill++;
}
}
const char * event_extra_get(const event_t *event, const event_extra_key_t key)
{
size_t i;
if (!event || !event->extra_entries)
return NULL;
for (i = 0; i < event->extra_fill; i++) {
if (event->extra_entries[i].key == key)
return event->extra_entries[i].value;
}
return NULL;
}
const char * event_extra_key_name(event_extra_key_t key)
{
switch (key) {
case EVENT_EXTRA_KEY_URI: return "uri"; break;
case EVENT_EXTRA_KEY_CONNECTION_IP: return "connection-ip"; break;
case EVENT_EXTRA_KEY_CLIENT_ROLE: return "client-role"; break;
case EVENT_EXTRA_KEY_CLIENT_USERNAME: return "client-username"; break;
case EVENT_EXTRA_KEY_CLIENT_USERAGENT: return "client-useragent"; break;
case EVENT_EXTRA_KEY_SOURCE_MEDIA_TYPE: return "source-media-type"; break;
case EVENT_EXTRA_KEY_DUMPFILE_FILENAME: return "dumpfile-filename"; break;
#ifndef DEVEL_LOGGING
default: break;
#endif
}
return NULL;
}
igloo_error_t event_to_string_renderer(const event_t *event, string_renderer_t *renderer)
{
static const event_extra_key_t key_list[] = {
EVENT_EXTRA_KEY_URI,
EVENT_EXTRA_KEY_SOURCE_MEDIA_TYPE,
EVENT_EXTRA_KEY_CONNECTION_IP,
EVENT_EXTRA_KEY_CLIENT_ROLE,
EVENT_EXTRA_KEY_CLIENT_USERNAME,
EVENT_EXTRA_KEY_CLIENT_USERAGENT,
EVENT_EXTRA_KEY_DUMPFILE_FILENAME,
EVENT_EXTRA_LIST_END
};
string_renderer_add_kv_with_options(renderer, "trigger", event->trigger, STRING_RENDERER_ENCODING_PLAIN, false, false);
for (size_t i = 0; key_list[i] != EVENT_EXTRA_LIST_END; i++) {
string_renderer_add_kv_with_options(renderer, event_extra_key_name(key_list[i]), event_extra_get(event, key_list[i]), STRING_RENDERER_ENCODING_PLAIN, false, false);
}
if (event->client_data) {
string_renderer_add_ki_with_options(renderer, "connection-id", event->connection_id, STRING_RENDERER_ENCODING_PLAIN, true, false);
string_renderer_add_ki_with_options(renderer, "connection-time", event->connection_time, STRING_RENDERER_ENCODING_PLAIN, true, false);
string_renderer_add_ki_with_options(renderer, "client-admin-command", event->client_admin_command, STRING_RENDERER_ENCODING_PLAIN, true, false);
}
return igloo_ERROR_NONE;
}
/* work with event_t* */
static void event_addref(event_t *event) {
if (!event)
@ -58,11 +146,11 @@ static void event_release(event_t *event) {
event_registration_release(event->reglist[i]);
free(event->trigger);
free(event->uri);
free(event->connection_ip);
free(event->client_role);
free(event->client_username);
free(event->client_useragent);
for (i = 0; i < event->extra_fill; i++)
igloo_sp_unref(&(event->extra_entries[i].value), igloo_instance);
free(event->extra_entries);
to_free = event->next;
free(event);
thread_mutex_unlock(&event_lock);
@ -362,19 +450,39 @@ void event_emit(event_t *event) {
thread_mutex_unlock(&event_lock);
}
/* this function needs to extract all the info from the client, source and mount object
* as after return the pointers become invalid.
*/
void event_emit_clientevent(const char *trigger, client_t *client, const char *uri) {
void event_emit_va(const char *trigger, ...) {
event_t *event = event_new(trigger);
source_t *source = NULL;
client_t *client = NULL;
const char *uri = NULL;
ice_config_t *config;
mount_proxy *mount;
const mount_proxy *mount;
va_list ap;
if (!event) {
ICECAST_LOG_ERROR("Can not create event.");
return;
}
va_start(ap, trigger);
while (true) {
event_extra_key_t key = va_arg(ap, event_extra_key_t);
if (key == EVENT_EXTRA_LIST_END) {
break;
} else if (key == EVENT_EXTRA_KEY_URI) {
uri = va_arg(ap, const char *);
} else if (key == EVENT_EXTRA_SOURCE) {
source = va_arg(ap, source_t *);
} else if (key == EVENT_EXTRA_CLIENT) {
client = va_arg(ap, client_t *);
}
}
va_end(ap);
if (source && !uri)
uri = source->mount;
config = config_get_config();
event_push_reglist(event, config->event);
@ -402,24 +510,43 @@ void event_emit_clientevent(const char *trigger, client_t *client, const char *u
}
#endif
if (uri)
extra_add(event, EVENT_EXTRA_KEY_URI, uri);
va_start(ap, trigger);
while (true) {
event_extra_key_t key = va_arg(ap, event_extra_key_t);
if (key == EVENT_EXTRA_LIST_END) {
break;
} else if (key == EVENT_EXTRA_SOURCE || key == EVENT_EXTRA_CLIENT) {
/* shift one arg off */
va_arg(ap, const void *);
} else {
const char *value = va_arg(ap, const char *);
extra_add(event, key, value);
}
}
va_end(ap);
if (source) {
if (source->format && source->format->contenttype) {
extra_add(event, EVENT_EXTRA_KEY_SOURCE_MEDIA_TYPE, source->format->contenttype);
}
}
if (client) {
const char *tmp;
event->client_data = true;
event->connection_id = client->con->id;
event->connection_time = client->con->con_time;
event->client_admin_command = client->admin_command;
event->connection_ip = strdup(client->con->ip);
if (client->role)
event->client_role = strdup(client->role);
if (client->username)
event->client_username = strdup(client->username);
tmp = httpp_getvar(client->parser, "user-agent");
if (tmp)
event->client_useragent = strdup(tmp);
extra_add(event, EVENT_EXTRA_KEY_CONNECTION_IP, client->con->ip);
extra_add(event, EVENT_EXTRA_KEY_CLIENT_ROLE, client->role);
extra_add(event, EVENT_EXTRA_KEY_CLIENT_USERNAME, client->username);
extra_add(event, EVENT_EXTRA_KEY_CLIENT_USERAGENT, httpp_getvar(client->parser, "user-agent"));
}
if (uri)
event->uri = strdup(uri);
event_emit(event);
event_release(event);
}

View File

@ -9,10 +9,14 @@
#ifndef __EVENT_H__
#define __EVENT_H__
#include <stdbool.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <igloo/error.h>
#include "common/thread/thread.h"
#include "icecasttypes.h"
@ -25,6 +29,26 @@
#define MAX_REGLISTS_PER_EVENT 8
typedef enum {
/* special keys */
EVENT_EXTRA_LIST_END,
EVENT_EXTRA_CLIENT,
EVENT_EXTRA_SOURCE,
/* real keys */
EVENT_EXTRA_KEY_URI,
EVENT_EXTRA_KEY_CONNECTION_IP,
EVENT_EXTRA_KEY_CLIENT_ROLE,
EVENT_EXTRA_KEY_CLIENT_USERNAME,
EVENT_EXTRA_KEY_CLIENT_USERAGENT,
EVENT_EXTRA_KEY_SOURCE_MEDIA_TYPE,
EVENT_EXTRA_KEY_DUMPFILE_FILENAME,
} event_extra_key_t;
typedef struct {
event_extra_key_t key;
const char *value;
} event_extra_entry_t;
struct event_registration_tag;
typedef struct event_registration_tag event_registration_t;
@ -49,14 +73,14 @@ struct event_tag {
char *trigger;
/* from client */
char *uri; /* from context */
bool client_data;
unsigned long connection_id; /* from client->con->id */
char *connection_ip; /* from client->con->ip */
time_t connection_time; /* from client->con->con_time */
char *client_role; /* from client->role */
char *client_username; /* from client->username */
char *client_useragent; /* from httpp_getvar(client->parser, "user-agent") */
admin_command_id_t client_admin_command; /* from client->admin_command */
/* extra */
size_t extra_size;
size_t extra_fill;
event_extra_entry_t *extra_entries;
};
struct event_registration_tag {
@ -97,8 +121,13 @@ void event_registration_release(event_registration_t *er);
void event_registration_push(event_registration_t **er, event_registration_t *tail);
/* event signaling */
void event_emit_clientevent(const char *trigger, client_t *client, const char *uri);
#define event_emit_global(x) event_emit_clientevent((x), NULL, NULL)
void event_emit_va(const char *trigger, ...);
#define event_emit_global(event) event_emit_va((event), EVENT_EXTRA_LIST_END)
/* reading extra from events */
const char * event_extra_get(const event_t *event, const event_extra_key_t key);
const char * event_extra_key_name(event_extra_key_t key);
igloo_error_t event_to_string_renderer(const event_t *event, string_renderer_t *renderer); /* expects renderer in list mode */
/* Implementations */
int event_get_exec(event_registration_t *er, config_options_t *options);

View File

@ -10,6 +10,7 @@
#include <config.h>
#endif
#include <unistd.h>
#include <string.h>
#include <errno.h>
@ -46,6 +47,13 @@ typedef struct event_exec {
char **argv;
} event_exec_t;
static char *_null_aware_strdup(const char *s)
{
if (!s)
return NULL;
return strdup(s);
}
/* OS independed code: */
static inline size_t __argvtype2offset(event_exec_argvtype_t argvtype) {
switch (argvtype) {
@ -79,6 +87,8 @@ static inline event_exec_argvtype_t __str2argvtype(const char *str) {
}
static inline char **__setup_argv(event_exec_t *self, event_t *event) {
char *uri;
self->argv[0] = self->executable;
switch (self->argvtype) {
@ -89,14 +99,16 @@ static inline char **__setup_argv(event_exec_t *self, event_t *event) {
self->argv[2] = event->trigger ? event->trigger : "";
/* fall through */
case ARGVTYPE_ONLY_URI:
self->argv[1] = event->uri ? event->uri : "";
uri = _null_aware_strdup(event_extra_get(event, EVENT_EXTRA_KEY_URI));
self->argv[1] = uri ? uri : "";
break;
case ARGVTYPE_LEGACY:
/* This mode is similar to ARGVTYPE_ONLY_URI
* but if URI is unknown the parameter is skipped!
*/
if (event->uri) {
self->argv[1] = event->uri;
uri = _null_aware_strdup(event_extra_get(event, EVENT_EXTRA_KEY_URI));
if (uri) {
self->argv[1] = uri;
} else {
self->argv[1] = self->executable;
return &self->argv[1];
@ -122,6 +134,12 @@ static inline void __update_environ(const char *name, const char *value) {
#else
#define __update_environ(x,y)
#endif
static inline void __update_environ_with_key(const event_t *event, const char *name, event_extra_key_t key)
{
__update_environ(name, event_extra_get(event, key));
}
static inline void __setup_environ(ice_config_t *config, event_exec_t *self, event_t *event) {
mount_proxy *mountinfo;
source_t *source;
@ -132,13 +150,15 @@ static inline void __setup_environ(ice_config_t *config, event_exec_t *self, eve
__update_environ("ICECAST_HOSTNAME", config->hostname);
__update_environ("ICECAST_ADMIN", config->admin);
__update_environ("ICECAST_LOGDIR", config->log_dir);
__update_environ("EVENT_URI", event->uri);
__update_environ("EVENT_TRIGGER", event->trigger); /* new name */
__update_environ("SOURCE_ACTION", event->trigger); /* old name (deprecated) */
__update_environ("CLIENT_IP", event->connection_ip);
__update_environ("CLIENT_ROLE", event->client_role);
__update_environ("CLIENT_USERNAME", event->client_username);
__update_environ("CLIENT_USERAGENT", event->client_useragent);
__update_environ_with_key(event, "EVENT_URI", EVENT_EXTRA_KEY_URI);
__update_environ_with_key(event, "SOURCE_MEDIA_TYPE", EVENT_EXTRA_KEY_SOURCE_MEDIA_TYPE);
__update_environ_with_key(event, "CLIENT_IP", EVENT_EXTRA_KEY_CONNECTION_IP);
__update_environ_with_key(event, "CLIENT_ROLE", EVENT_EXTRA_KEY_CLIENT_ROLE);
__update_environ_with_key(event, "CLIENT_USERNAME", EVENT_EXTRA_KEY_CLIENT_USERNAME);
__update_environ_with_key(event, "CLIENT_USERAGENT", EVENT_EXTRA_KEY_CLIENT_USERAGENT);
__update_environ_with_key(event, "DUMPFILE_FILENAME", EVENT_EXTRA_KEY_DUMPFILE_FILENAME);
snprintf(buf, sizeof(buf), "%lu", event->connection_id);
__update_environ("CLIENT_ID", buf);
@ -147,7 +167,7 @@ static inline void __setup_environ(ice_config_t *config, event_exec_t *self, eve
snprintf(buf, sizeof(buf), "%i", event->client_admin_command);
__update_environ("CLIENT_ADMIN_COMMAND", buf);
mountinfo = config_find_mount(config, event->uri, MOUNT_TYPE_NORMAL);
mountinfo = config_find_mount(config, event_extra_get(event, EVENT_EXTRA_KEY_URI), MOUNT_TYPE_NORMAL);
if (mountinfo) {
__update_environ("MOUNT_NAME", mountinfo->stream_name);
__update_environ("MOUNT_DESCRIPTION", mountinfo->stream_description);
@ -156,7 +176,7 @@ static inline void __setup_environ(ice_config_t *config, event_exec_t *self, eve
}
avl_tree_rlock(global.source_tree);
source = source_find_mount(event->uri);
source = source_find_mount(event_extra_get(event, EVENT_EXTRA_KEY_URI));
if (source) {
__update_environ("SOURCE_MOUNTPOINT", source->mount);
__update_environ("SOURCE_PUBLIC", source->yp_public ? "true" : "false");
@ -223,7 +243,7 @@ static void _run_script (event_exec_t *self, event_t *event) {
default: /* parent */
break;
}
exit (0);
_exit(0);
case -1:
ICECAST_LOG_ERROR("Unable to fork %s", strerror (errno));
break;

View File

@ -12,7 +12,13 @@
#include <string.h>
#include "icecasttypes.h"
#include <igloo/ro.h>
#include <igloo/error.h>
#include "event.h"
#include "global.h" /* for igloo_instance */
#include "string_renderer.h"
#include "util.h"
#include "cfgfile.h"
#include "logging.h"
@ -24,18 +30,24 @@ typedef struct event_log {
int level;
} event_log_t;
static int event_log_emit(void *state, event_t *event) {
event_log_t *self = state;
string_renderer_t * renderer;
if (igloo_ro_new(&renderer, string_renderer_t, igloo_instance) != igloo_ERROR_NONE)
return 0;
string_renderer_start_list(renderer, " ", "=", false, false, STRING_RENDERER_ENCODING_H_ALT_SPACE);
event_to_string_renderer(event, renderer);
string_renderer_end_list(renderer);
ICECAST_LOG(self->level, ICECAST_LOGFLAG_NONE,
"%s%strigger=%# H uri=%#H "
"connection_id=%lu connection_ip=%#H connection_time=%lli "
"client_role=%# H client_username=%#H client_useragent=%# H client_admin_command=%i",
"%s%s%s",
self->prefix ? self->prefix : "", self->prefix ? ": " : "",
event->trigger,
event->uri,
event->connection_id, event->connection_ip, (long long int)event->connection_time,
event->client_role, event->client_username, event->client_useragent, event->client_admin_command);
string_renderer_to_string_zero_copy(renderer));
igloo_ro_unref(&renderer);
return 0;
}

View File

@ -11,7 +11,14 @@
#endif
#include <string.h>
#include <stdbool.h>
#include "icecasttypes.h"
#include <igloo/ro.h>
#include <igloo/error.h>
#include "global.h" /* for igloo_instance */
#include "string_renderer.h"
#include "curl.h"
#include "event.h"
#include "cfgfile.h"
@ -21,6 +28,7 @@
typedef struct event_url {
bool legacy;
char *url;
char *action;
char *userpwd;
@ -43,39 +51,45 @@ static inline char *__escape(const char *src, const char *default_value) {
static int event_url_emit(void *state, event_t *event) {
event_url_t *self = state;
ice_config_t *config;
char *action, *mount, *server, *role, *username, *ip, *agent;
time_t duration;
char post[4096];
string_renderer_t * renderer;
action = util_url_escape(self->action ? self->action : event->trigger);
mount = __escape(event->uri, "");
role = __escape(event->client_role, "");
username = __escape(event->client_username, "");
ip = __escape(event->connection_ip, "");
agent = __escape(event->client_useragent, "-");
if (igloo_ro_new(&renderer, string_renderer_t, igloo_instance) != igloo_ERROR_NONE)
return 0;
if (event->connection_time) {
if (event->client_data) {
duration = time(NULL) - event->connection_time;
} else {
duration = 0;
}
config = config_get_config();
server = __escape(config->hostname, "");
string_renderer_start_list_formdata(renderer);
if (self->legacy) {
/* Old style */
string_renderer_add_kv_with_options(renderer, "action", self->action ? self->action : event->trigger, STRING_RENDERER_ENCODING_PLAIN, false, false);
string_renderer_add_kv_with_options(renderer, "mount", event_extra_get(event, EVENT_EXTRA_KEY_URI), STRING_RENDERER_ENCODING_PLAIN, true, true);
string_renderer_add_ki_with_options(renderer, "client", event->connection_id, STRING_RENDERER_ENCODING_PLAIN, true, true);
string_renderer_add_kv_with_options(renderer, "role", event_extra_get(event, EVENT_EXTRA_KEY_CLIENT_ROLE), STRING_RENDERER_ENCODING_PLAIN, true, true);
string_renderer_add_kv_with_options(renderer, "username", event_extra_get(event, EVENT_EXTRA_KEY_CLIENT_USERNAME), STRING_RENDERER_ENCODING_PLAIN, true, true);
string_renderer_add_kv_with_options(renderer, "ip", event_extra_get(event, EVENT_EXTRA_KEY_CONNECTION_IP), STRING_RENDERER_ENCODING_PLAIN, true, true);
string_renderer_add_kv_with_options(renderer, "agent", event_extra_get(event, EVENT_EXTRA_KEY_CLIENT_USERAGENT) ? event_extra_get(event, EVENT_EXTRA_KEY_CLIENT_USERAGENT) : "-", STRING_RENDERER_ENCODING_PLAIN, true, true);
string_renderer_add_ki_with_options(renderer, "duration", duration, STRING_RENDERER_ENCODING_PLAIN, true, true);
string_renderer_add_ki_with_options(renderer, "admin", event->client_admin_command, STRING_RENDERER_ENCODING_PLAIN, true, true);
} else {
/* new style */
event_to_string_renderer(event, renderer);
}
snprintf (post, sizeof (post),
"action=%s&mount=%s&server=%s&port=%d&client=%lu&role=%s&username=%s&ip=%s&agent=%s&duration=%lli&admin=%i",
action, mount, server, config->port,
event->connection_id, role, username, ip, agent, (long long int)duration, event->client_admin_command);
/* common */
config = config_get_config();
string_renderer_add_kv_with_options(renderer, "server", config->hostname, STRING_RENDERER_ENCODING_PLAIN, true, true);
if (self->legacy) {
string_renderer_add_ki_with_options(renderer, "port", config->port, STRING_RENDERER_ENCODING_PLAIN, true, true);
}
config_release_config();
free(action);
free(mount);
free(server);
free(role);
free(username);
free(ip);
free(agent);
string_renderer_end_list(renderer);
if (strchr(self->url, '@') == NULL && self->userpwd) {
curl_easy_setopt(self->handle, CURLOPT_USERPWD, self->userpwd);
@ -84,11 +98,13 @@ static int event_url_emit(void *state, event_t *event) {
}
curl_easy_setopt(self->handle, CURLOPT_URL, self->url);
curl_easy_setopt(self->handle, CURLOPT_POSTFIELDS, post);
curl_easy_setopt(self->handle, CURLOPT_POSTFIELDS, string_renderer_to_string_zero_copy(renderer));
if (curl_easy_perform(self->handle))
ICECAST_LOG_WARN("auth to server %s failed with %s", self->url, self->errormsg);
igloo_ro_unref(&renderer);
return 0;
}
@ -109,6 +125,8 @@ int event_get_url(event_registration_t *er, config_options_t *options) {
if (!self)
return -1;
self->legacy = true;
if (options) {
do {
if (options->type)
@ -129,6 +147,8 @@ int event_get_url(event_registration_t *er, config_options_t *options) {
password = options->value;
} else if (strcmp(options->name, "action") == 0) {
util_replace_string(&(self->action), options->value);
} else if (strcmp(options->name, "legacy") == 0) {
self->legacy = util_str_to_bool(options->value);
} else {
ICECAST_LOG_ERROR("Unknown <option> tag with name %s.", options->name);
}

View File

@ -627,19 +627,19 @@ static bool source_open_dumpfile(source_t *source)
if (!filename) {
ICECAST_LOG_WARN("Can not open dump file for source %#H. No filename defined.", source->mount);
event_emit_clientevent("dumpfile-error", NULL, source->mount);
event_emit_va("dumpfile-error", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_LIST_END);
return false;
}
if (source->dumpfile) {
ICECAST_LOG_WARN("Can not open dump file for source %#H. Dump already running.", source->mount);
event_emit_clientevent("dumpfile-error", NULL, source->mount);
event_emit_va("dumpfile-error", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_LIST_END);
return false;
}
if (!source->format->write_buf_to_file) {
ICECAST_LOG_WARN("Can not open dump file for source %#H. format does not support dumping.", source->mount);
event_emit_clientevent("dumpfile-error", NULL, source->mount);
event_emit_va("dumpfile-error", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_LIST_END);
return false;
}
@ -659,12 +659,12 @@ static bool source_open_dumpfile(source_t *source)
source->dumpfile_start = curtime;
stats_event(source->mount, "dumpfile_written", "0");
stats_event_time_iso8601(source->mount, "dumpfile_start");
event_emit_clientevent("dumpfile-opened", NULL, source->mount);
event_emit_va("dumpfile-opened", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_KEY_DUMPFILE_FILENAME, filename, EVENT_EXTRA_LIST_END);
return true;
} else {
ICECAST_LOG_WARN("Cannot open dump file for source %#H with filename %#H for appending: %s, disabling.",
source->mount, source->dumpfilename, strerror(errno));
event_emit_clientevent("dumpfile-error", NULL, source->mount);
event_emit_va("dumpfile-error", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_KEY_DUMPFILE_FILENAME, filename, EVENT_EXTRA_LIST_END);
return false;
}
}
@ -712,7 +712,7 @@ static void source_init (source_t *source)
source->prev_listeners = -1;
source->running = 1;
event_emit_clientevent("source-connect", source->client, source->mount);
event_emit_va("source-connect", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_CLIENT, source->client, EVENT_EXTRA_LIST_END);
/*
** Now, if we have a fallback source and override is on, we want
@ -927,7 +927,7 @@ static void source_shutdown (source_t *source)
ICECAST_LOG_INFO("Source at \"%s\" exiting", source->mount);
}
event_emit_clientevent("source-disconnect", source->client, source->mount);
event_emit_va("source-disconnect", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_CLIENT, source->client, EVENT_EXTRA_LIST_END);
/* we have de-activated the source now, so no more clients will be
* added, now move the listeners we have to the fallback (if any)
@ -1051,12 +1051,15 @@ static void source_apply_mount (ice_config_t *config, source_t *source, mount_pr
int val;
http_parser_t *parser = NULL;
acl_t *acl = NULL;
source_flags_t old_flags = source->flags;
ICECAST_LOG_DEBUG("Applying mount information for \"%s\"", source->mount);
avl_tree_rlock (source->client_tree);
stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
source->flags &= ~SOURCE_FLAGS_CLEARABLE;
if (old_flags != source->flags)
event_emit_va("source-flags-changed", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_LIST_END);
if (mountinfo)
{
@ -1562,7 +1565,7 @@ void source_kill_dumpfile(source_t *source)
source->dumpfile_written = 0;
stats_event(source->mount, "dumpfile_written", NULL);
stats_event(source->mount, "dumpfile_start", NULL);
event_emit_clientevent("dumpfile-closed", NULL, source->mount);
event_emit_va("dumpfile-closed", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_LIST_END);
}
health_t source_get_health(source_t *source)
@ -1592,11 +1595,19 @@ health_t source_get_health_by_flags(source_flags_t flags)
void source_set_flags(source_t *source, source_flags_t flags)
{
bool changed;
source_flags_t old_flags;
/* check if we need to do anything at all */
if ((source->flags & flags) == flags)
return;
thread_mutex_lock(&source->lock);
old_flags = source->flags;
source->flags |= flags;
changed = old_flags != source->flags;
thread_mutex_unlock(&source->lock);
if (changed)
event_emit_va("source-flags-changed", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_LIST_END);
}