...
 
Commits (29)
## Process this file with automake to produce Makefile.in
admindir = $(pkgdatadir)/admin
nobase_dist_admin_DATA = listclients.xsl listmounts.xsl moveclients.xsl response.xsl \
stats.xsl manageauth.xsl updatemetadata.xsl xspf.xsl vclt.xsl includes/footer.xsl \
includes/head.xsl includes/header.xsl includes/page.xsl includes/mountnav.xsl
nobase_dist_admin_DATA = \
listclients.xsl \
listmounts.xsl \
moveclients.xsl \
response.xsl \
stats.xsl \
manageauth.xsl \
updatemetadata.xsl \
error-html.xsl \
error-plaintext.xsl \
xspf.xsl \
vclt.xsl \
includes/footer.xsl \
includes/head.xsl \
includes/header.xsl \
includes/page.xsl \
includes/mountnav.xsl \
includes/web-page.xsl
......@@ -37,6 +37,35 @@ AM_MAINTAINER_MODE([enable])
LT_INIT
dnl Sanitizer flags
AC_ARG_WITH([sanitizer],
[AS_HELP_STRING([--with-sanitizer=(address/memory/undefined/thread)],
[build with sanitizer flags (default disabled)])],
[],
[with_sanitizer=no])
AS_VAR_IF(with_sanitizer, no, [], [
AX_CHECK_COMPILE_FLAG([-fsanitize=${with_sanitizer}], [
AX_APPEND_FLAG([-fsanitize=${with_sanitizer}])
AX_APPEND_FLAG([-fsanitize=${with_sanitizer}], [LDFLAGS])
], [
AC_MSG_ERROR(["-fsanitize=${with_sanitizer} not supported!"])
])
AX_APPEND_FLAG([-g])
AS_IF([test -z "${with_sanitizer##*address*}" ], [
AX_APPEND_COMPILE_FLAGS([-fsanitize-address-use-after-scope -fno-omit-frame-pointer -fsanitize=pointer-compare -fsanitize=pointer-subtract])
])
AS_IF([test -z "${with_sanitizer##*memory*}" ], [
AX_APPEND_COMPILE_FLAGS([-fPIE -pie])
])
AS_IF([test -z "${with_sanitizer##*thread*}" ], [
AX_APPEND_COMPILE_FLAGS([-fPIE -pie])
])
])
dnl Check for attributes
AX_GCC_TYPE_ATTRIBUTE([transparent_union])
......
......@@ -7,6 +7,7 @@ bin_PROGRAMS = icecast
noinst_HEADERS = \
icecasttypes.h \
admin.h \
resourcematch.h \
main.h \
cfgfile.h \
logging.h \
......@@ -33,6 +34,7 @@ noinst_HEADERS = \
module.h \
reportxml.h \
listensocket.h \
fastevent.h \
event.h \
event_log.h \
event_exec.h \
......@@ -69,6 +71,7 @@ icecast_SOURCES = \
xslt.c \
fserve.c \
admin.c \
resourcematch.c \
md5.c \
matchfile.c \
tls.c \
......@@ -76,6 +79,7 @@ icecast_SOURCES = \
module.c \
reportxml.c \
listensocket.c \
fastevent.c \
format.c \
format_ogg.c \
format_mp3.c \
......
This diff is collapsed.
......@@ -19,6 +19,7 @@
#include "icecasttypes.h"
#include "compat.h"
#include "resourcematch.h"
/* types */
#define ADMINTYPE_ERROR (-1)
......@@ -31,12 +32,14 @@
#define ADMIN_COMMAND_ANY ((admin_command_id_t)0) /* for ACL framework */
typedef void (*admin_request_function_ptr)(client_t * client, source_t * source, admin_format_t format);
typedef void (*admin_request_function_with_parameters_ptr)(client_t * client, source_t * source, admin_format_t format, resourcematch_extract_t *parameters);
typedef struct admin_command_handler {
const char *route;
const int type;
const int format;
const admin_request_function_ptr function;
const admin_request_function_with_parameters_ptr function_with_parameters;
} admin_command_handler_t;
void admin_handle_request(client_t *client, const char *uri);
......
......@@ -44,6 +44,7 @@
#include "connection.h"
#include "main.h"
#include "slave.h"
#include "xslt.h"
#define CATMODULE "CONFIG"
#define CONFIG_DEFAULT_LOCATION "Earth"
......@@ -748,6 +749,7 @@ void config_reread_config(void)
stats_global(config);
config_release_config();
slave_update_all_mounts();
xslt_clear_cache();
}
}
......@@ -2150,6 +2152,7 @@ static void _parse_paths(xmlDocPtr doc,
ICECAST_LOG_ERROR("Can not parse report xml database \"%H\"", temp);
} else {
reportxml_database_add_report(configuration->reportxml_db, report);
refobject_unref(report);
ICECAST_LOG_INFO("File \"%H\" added to report xml database", temp);
}
}
......
......@@ -49,6 +49,7 @@
#include "util.h"
#include "acl.h"
#include "listensocket.h"
#include "fastevent.h"
/* for ADMIN_COMMAND_ERROR */
#include "admin.h"
......@@ -100,6 +101,8 @@ int client_create(client_t **c_ptr, connection_t *con, http_parser_t *parser)
client->write_to_client = format_generic_write_to_client;
*c_ptr = client;
fastevent_emit(FASTEVENT_TYPE_CLIENT_CREATE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
return ret;
}
......@@ -153,6 +156,8 @@ void client_destroy(client_t *client)
if (client == NULL)
return;
fastevent_emit(FASTEVENT_TYPE_CLIENT_DESTROY, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
if (client->reuse != ICECAST_REUSE_CLOSE) {
/* only reuse the client if we reached the body's EOF. */
if (client_body_eof(client) == 1) {
......@@ -237,6 +242,8 @@ int client_read_bytes(client_t *client, void *buf, unsigned len)
if (bytes == -1 && client->con->error)
ICECAST_LOG_DEBUG("reading from connection has failed");
fastevent_emit(FASTEVENT_TYPE_CLIENT_READ, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_OBRD, client, buf, (size_t)len, (ssize_t)bytes);
return bytes;
}
......@@ -334,6 +341,8 @@ void client_send_101(client_t *client, reuse_t reuse)
client->respcode = 101;
client->refbuf->len = strlen(client->refbuf->data);
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
fserve_add_client(client, NULL);
}
......@@ -357,6 +366,8 @@ void client_send_204(client_t *client)
client->respcode = 204;
client->refbuf->len = strlen(client->refbuf->data);
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
fserve_add_client(client, NULL);
}
......@@ -387,6 +398,8 @@ void client_send_426(client_t *client, reuse_t reuse)
client->reuse = ICECAST_REUSE_KEEPALIVE;
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
fserve_add_client(client, NULL);
}
......@@ -398,6 +411,10 @@ static inline void client_send_500(client_t *client, const char *message)
const ssize_t header_len = sizeof(header) - 1;
ssize_t ret;
client->respcode = 500;
client->refbuf->len = 0;
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
ret = client_send_bytes(client, header, header_len);
/* only send message if we have one AND if header could have transmitted completly */
......@@ -517,6 +534,7 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
client->refbuf->len = ret;
xmlFree(buff);
client->respcode = status;
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
fserve_add_client (client, NULL);
} else {
char *fullpath_xslt_template;
......@@ -545,6 +563,7 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
config_release_config();
ICECAST_LOG_DEBUG("Sending XSLT (%s)", fullpath_xslt_template);
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
xslt_transform(doc, fullpath_xslt_template, client, status);
free(fullpath_xslt_template);
}
......@@ -580,6 +599,8 @@ int client_send_bytes(client_t *client, const void *buf, unsigned len)
if (client->con->error)
ICECAST_LOG_DEBUG("Client connection died");
fastevent_emit(FASTEVENT_TYPE_CLIENT_WRITE, FASTEVENT_FLAG_NONE, FASTEVENT_DATATYPE_OBRD, client, buf, (size_t)len, (ssize_t)ret);
return ret;
}
......@@ -615,6 +636,8 @@ ssize_t client_body_read(client_t *client, void *buf, size_t len)
client->request_body_read += ret;
}
fastevent_emit(FASTEVENT_TYPE_CLIENT_READ_BODY, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_OBRD, client, buf, len, ret);
return ret;
}
......
......@@ -39,24 +39,29 @@
# endif
#endif
/* Make sure we define 64 bit types */
#ifdef _WIN32
# define PATH_SEPARATOR "\\"
#else
# define PATH_SEPARATOR "/"
#endif
/* Make sure we define 64 bit types */
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#if defined(_WIN32) && !defined(HAVE_STDINT_H) && !defined(HAVE_INTTYPES_H)
# define size_t unsigned int
# define ssize_t int
# define int64_t __int64
# define uint64_t unsigned __int64
# define uint32_t unsigned int
# define int32_t __int32
# define uint32_t unsigned __int32
# define PRIu64 "I64u"
# define PRId64 "I64d"
#else
# define PATH_SEPARATOR "/"
# ifdef HAVE_STDINT_H
# include <stdint.h>
# endif
# ifdef HAVE_INTTYPES_H
# include <inttypes.h>
# endif
#endif
/* some defaults if not provided above */
......
......@@ -60,6 +60,7 @@
#include "acl.h"
#include "refobject.h"
#include "listensocket.h"
#include "fastevent.h"
#define CATMODULE "connection"
......@@ -90,7 +91,7 @@ typedef struct client_queue_tag {
} client_queue_t;
static spin_t _connection_lock; // protects _current_id, _con_queue, _con_queue_tail
static volatile unsigned long _current_id = 0;
static volatile connection_id_t _current_id = 0;
static int _initialized = 0;
static volatile client_queue_t *_req_queue = NULL, **_req_queue_tail = &_req_queue;
......@@ -149,9 +150,9 @@ void connection_reread_config(ice_config_t *config)
listensocket_container_configure_and_setup(global.listensockets, config);
}
static unsigned long _next_connection_id(void)
static connection_id_t _next_connection_id(void)
{
unsigned long id;
connection_id_t id;
thread_spin_lock(&_connection_lock);
id = _current_id++;
......@@ -209,6 +210,9 @@ static int connection_send_tls(connection_t *con, const void *buf, size_t len)
} else {
con->sent_bytes += bytes;
}
fastevent_emit(FASTEVENT_TYPE_CONNECTION_WRITE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_OBRD, con, buf, len, bytes);
return bytes;
}
#else
......@@ -245,6 +249,9 @@ static int connection_send(connection_t *con, const void *buf, size_t len)
} else {
con->sent_bytes += bytes;
}
fastevent_emit(FASTEVENT_TYPE_CONNECTION_WRITE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_OBRD, con, buf, len, (ssize_t)bytes);
return bytes;
}
......@@ -271,6 +278,8 @@ connection_t *connection_create(sock_t sock, listensocket_t *listensocket_real,
con->send = connection_send;
}
fastevent_emit(FASTEVENT_TYPE_CONNECTION_CREATE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CONNECTION, con);
return con;
}
......@@ -297,7 +306,7 @@ void connection_uses_tls(connection_t *con)
#endif
}
ssize_t connection_read_bytes(connection_t *con, void *buf, size_t len)
static inline ssize_t connection_read_bytes_real(connection_t *con, void *buf, size_t len)
{
ssize_t done = 0;
ssize_t ret;
......@@ -338,10 +347,21 @@ ssize_t connection_read_bytes(connection_t *con, void *buf, size_t len)
return done + ret;
}
ssize_t connection_read_bytes(connection_t *con, void *buf, size_t len)
{
ssize_t ret = connection_read_bytes_real(con, buf, len);
fastevent_emit(FASTEVENT_TYPE_CONNECTION_READ, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_OBRD, con, buf, len, ret);
return ret;
}
int connection_read_put_back(connection_t *con, const void *buf, size_t len)
{
void *n;
fastevent_emit(FASTEVENT_TYPE_CONNECTION_PUTBACK, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_OBR, con, buf, len);
if (con->readbufferlen) {
n = realloc(con->readbuffer, con->readbufferlen + len);
if (!n)
......@@ -1251,6 +1271,8 @@ static void _handle_authed_client(client_t *client, void *uri, auth_result resul
auth_stack_release(client->authstack);
client->authstack = NULL;
fastevent_emit(FASTEVENT_TYPE_CLIENT_AUTHED, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
if (result != AUTH_OK) {
client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE);
free(uri);
......@@ -1391,6 +1413,7 @@ static void _handle_authentication_mount_normal(client_t *client, char *uri)
static void _handle_authentication(client_t *client, char *uri)
{
fastevent_emit(FASTEVENT_TYPE_CLIENT_READY_FOR_AUTH, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
_handle_authentication_mount_normal(client, uri);
}
......@@ -1688,6 +1711,8 @@ void connection_close(connection_t *con)
if (!con)
return;
fastevent_emit(FASTEVENT_TYPE_CONNECTION_DESTROY, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CONNECTION, con);
tls_unref(con->tls);
if (con->sock != -1) /* TODO: do not use magic */
sock_close(con->sock);
......
......@@ -24,8 +24,10 @@
#include "common/thread/thread.h"
#include "common/net/sock.h"
typedef unsigned long connection_id_t;
struct connection_tag {
unsigned long id;
connection_id_t id;
time_t con_time;
time_t discon_time;
......
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/**
* Special fast event functions
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "common/thread/thread.h"
#include "fastevent.h"
#include "logging.h"
#define CATMODULE "fastevent"
#ifdef FASTEVENT_ENABLED
struct registration {
refobject_base_t __base;
fastevent_type_t type;
fastevent_cb_t cb;
fastevent_freecb_t freecb;
void *userdata;
};
struct eventrow {
size_t length;
size_t used;
struct registration **registrations;
};
static struct eventrow fastevent_registrations[FASTEVENT_TYPE__END];
static rwlock_t fastevent_lock;
static inline struct eventrow * __get_row(fastevent_type_t type)
{
size_t idx = type;
if (idx >= FASTEVENT_TYPE__END)
return NULL;
return &(fastevent_registrations[idx]);
}
static int __add_to_row(struct eventrow * row, struct registration *registration)
{
struct registration **n;
if (row == NULL)
return -1;
/* Check if we need to reallocate row space */
if (row->length == row->used) {
n = realloc(row->registrations, sizeof(*n)*(row->length + 4));
if (n == NULL) {
ICECAST_LOG_ERROR("Can not allocate row space.");
return -1;
}
row->registrations = n;
row->length += 4;
}
row->registrations[row->used++] = registration;
return 0;
}
static int __remove_from_row(struct eventrow * row, struct registration *registration)
{
size_t i;
if (row == NULL)
return -1;
for (i = 0; i < row->used; i++) {
if (row->registrations[i] == registration) {
memmove(&(row->registrations[i]), &(row->registrations[i+1]), sizeof(*(row->registrations))*(row->used - i - 1));
row->used--;
return 0;
}
}
return -1;
}
static void __unregister(refobject_t self, void **userdata)
{
struct registration *registration = REFOBJECT_TO_TYPE(self, struct registration *);
struct eventrow * row;
(void)userdata;
thread_rwlock_wlock(&fastevent_lock);
row = __get_row(registration->type);
if (__remove_from_row(row, registration) != 0) {
ICECAST_LOG_ERROR("Can not remove fast event from row. BUG.");
}
thread_rwlock_unlock(&fastevent_lock);
if (registration->freecb)
registration->freecb(&(registration->userdata));
if (registration->userdata != NULL)
free(registration->userdata);
}
int fastevent_initialize(void)
{
thread_rwlock_create(&fastevent_lock);
return 0;
}
int fastevent_shutdown(void)
{
size_t i;
thread_rwlock_wlock(&fastevent_lock);
for (i = 0; i < FASTEVENT_TYPE__END; i++) {
if (fastevent_registrations[i].used) {
ICECAST_LOG_ERROR("Subsystem shutdown but elements still in use. BUG.");
continue;
}
free(fastevent_registrations[i].registrations);
fastevent_registrations[i].registrations = NULL;
}
thread_rwlock_unlock(&fastevent_lock);
thread_rwlock_destroy(&fastevent_lock);
return 0;
}
refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fastevent_freecb_t freecb, void *userdata)
{
struct eventrow * row;
struct registration *registration;
refobject_t ret;
if (cb == NULL)
return REFOBJECT_NULL;
thread_rwlock_wlock(&fastevent_lock);
row = __get_row(type);
if (row == NULL) {
thread_rwlock_unlock(&fastevent_lock);
return REFOBJECT_NULL;
}
ret = refobject_new(sizeof(struct registration), __unregister, NULL, NULL, NULL);
if (REFOBJECT_IS_NULL(ret)) {
thread_rwlock_unlock(&fastevent_lock);
return REFOBJECT_NULL;
}
registration = REFOBJECT_TO_TYPE(ret, struct registration *);
registration->type = type;
registration->cb = cb;
registration->freecb = freecb;
registration->userdata = userdata;
if (__add_to_row(row, registration) != 0) {
thread_rwlock_unlock(&fastevent_lock);
refobject_unref(ret);
return REFOBJECT_NULL;
}
thread_rwlock_unlock(&fastevent_lock);
return ret;
}
void fastevent_emit(fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, ...)
{
struct eventrow * row;
va_list ap, apx;
size_t i;
ICECAST_LOG_DEBUG("event: type=%i, flags=%i, datatype=%i, ...", (int)type, (int)flags, (int)datatype);
thread_rwlock_rlock(&fastevent_lock);
row = __get_row(type);
if (row == NULL || row->used == 0) {
thread_rwlock_unlock(&fastevent_lock);
return;
}
va_start(ap, datatype);
for (i = 0; i < row->used; i++) {
va_copy(apx, ap);
row->registrations[i]->cb(row->registrations[i]->userdata, type, flags, datatype, apx);
va_end(apx);
}
thread_rwlock_unlock(&fastevent_lock);
va_end(ap);
}
#endif
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __FASTEVENT_H__
#define __FASTEVENT_H__
/* Add all conditions when to enable fast events here. */
#if 1
#define FASTEVENT_ENABLED
#endif
#include <stdarg.h>
#include <refobject.h>
typedef enum {
FASTEVENT_TYPE_SLOWEVENT = 0,
FASTEVENT_TYPE_CONNECTION_CREATE,
FASTEVENT_TYPE_CONNECTION_DESTROY,
FASTEVENT_TYPE_CONNECTION_READ,
FASTEVENT_TYPE_CONNECTION_PUTBACK,
FASTEVENT_TYPE_CONNECTION_WRITE,
FASTEVENT_TYPE_CLIENT_CREATE,
FASTEVENT_TYPE_CLIENT_DESTROY,
FASTEVENT_TYPE_CLIENT_READ,
FASTEVENT_TYPE_CLIENT_WRITE,
FASTEVENT_TYPE_CLIENT_READ_BODY,
FASTEVENT_TYPE_CLIENT_READY_FOR_AUTH,
FASTEVENT_TYPE_CLIENT_AUTHED,
FASTEVENT_TYPE_CLIENT_SEND_RESPONSE,
FASTEVENT_TYPE__END /* must be last element */
} fastevent_type_t;
typedef enum {
FASTEVENT_DATATYPE_NONE = 0,
FASTEVENT_DATATYPE_EVENT,
FASTEVENT_DATATYPE_CLIENT,
FASTEVENT_DATATYPE_CONNECTION,
FASTEVENT_DATATYPE_OBR, /* Object, const void *Buffer, size_t Request_length */
FASTEVENT_DATATYPE_OBRD /* Object, const void *Buffer, size_t Request_length, ssize_t Done_length */
} fastevent_datatype_t;
typedef int fastevent_flag_t;
#define FASTEVENT_FLAG_NONE ((fastevent_flag_t)0x0000)
#define FASTEVENT_FLAG_MODIFICATION_ALLOWED ((fastevent_flag_t)0x0001)
typedef void (*fastevent_cb_t)(const void *userdata, fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, va_list ap);
typedef void (*fastevent_freecb_t)(void **userdata);
#ifdef FASTEVENT_ENABLED
int fastevent_initialize(void);
int fastevent_shutdown(void);
refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fastevent_freecb_t freecb, void *userdata);
void fastevent_emit(fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, ...);
#else
#define fastevent_initialize() 0
#define fastevent_shutdown() 0
#define fastevent_register(type,cb,freecb,userdata) REFOBJECT_NULL
#define fastevent_emit(type,flags,datatype,...)
#endif
#endif
......@@ -16,7 +16,7 @@
#ifdef HAVE_POLL
#include <poll.h>
#else
#elif HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
......
......@@ -78,6 +78,7 @@
#include "auth.h"
#include "event.h"
#include "listensocket.h"
#include "fastevent.h"
#include <libxml/xmlmemory.h>
......@@ -124,6 +125,7 @@ static void initialize_subsystems(void)
log_initialize();
thread_initialize();
global_initialize();
fastevent_initialize();
sock_initialize();
resolver_initialize();
config_initialize();
......@@ -152,6 +154,7 @@ static void shutdown_subsystems(void)
config_shutdown();
resolver_shutdown();
sock_shutdown();
fastevent_shutdown();
global_shutdown();
thread_shutdown();
......
......@@ -458,9 +458,11 @@ reportxml_node_t * reportxml_node_parse_xmlnode(xmlNodePtr xmlnode)
}
if (reportxml_node_add_child(node, child) != 0) {
refobject_unref(child);
refobject_unref(node);
return NULL;
}
refobject_unref(child);
}
} while ((cur = cur->next));
}
......@@ -522,6 +524,8 @@ static reportxml_node_t * __reportxml_node_copy_with_db(reportxml_node_t *n
refobject_unref(ret);
return NULL;
}
refobject_unref(copy);
}
}
......@@ -840,7 +844,7 @@ int reportxml_node_add_xml_child(reportxml_node_t *node, xml
node->xml_childs = n;
node->xml_childs[node->xml_childs_len] = xmlCopyNode(child, 2);
node->xml_childs[node->xml_childs_len] = xmlCopyNode(child, 1);
if (node->xml_childs[node->xml_childs_len] == NULL)
return -1;
......@@ -867,7 +871,7 @@ xmlNodePtr reportxml_node_get_xml_child(reportxml_node_t *node, siz
if (idx >= node->xml_childs_len)
return NULL;
ret = xmlCopyNode(node->xml_childs[idx], 2);
ret = xmlCopyNode(node->xml_childs[idx], 1);
return ret;
}
......@@ -959,6 +963,8 @@ int reportxml_database_add_report(reportxml_database_t *db,
thread_mutex_unlock(&(db->lock));
refobject_unref(root);
return 0;
}
......
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <errno.h>
#include "resourcematch.h"
static size_t count_groups(const char *pattern)
{
size_t ret = 0;
while (*pattern) {
for (; *pattern && *pattern != '%'; pattern++);
if (!*pattern) {
return ret;
}
pattern++;
if (!*pattern)
return ret;
if (*pattern != '%')
ret++;
pattern++;
}
return ret;
}
static resourcematch_extract_t * allocate_extract(const char *pattern)
{
size_t groups = count_groups(pattern);
resourcematch_extract_t *ret;
ret = calloc(1, sizeof(*ret));
if (!ret)
return NULL;
ret->groups = groups;
ret->group = calloc(groups, sizeof(*ret->group));
return ret;
}
static void strip_common_prefix(const char **pattern, const char **string)
{
const char *p = *pattern;
const char *s = *string;
for (; *p && *p != '%' && *p == *s; p++, s++);
*pattern = p;
*string = s;
}
static inline void setup_group(resourcematch_extract_t *extract, size_t idx, char type)
{
if (!extract)
return;
extract->group[idx].type = type;
extract->group[idx].raw = NULL;
}
static inline resourcematch_result_t match_lli(const char **string, resourcematch_extract_t *extract, size_t idx, int base)
{
long long int ret;
char *endptr;
errno = 0;
ret = strtoll(*string, &endptr, base);
if (errno != 0)
return RESOURCEMATCH_ERROR;
if (extract) {
extract->group[idx].result.lli = ret;
}
*string = endptr;
return RESOURCEMATCH_MATCH;
}
resourcematch_result_t resourcematch_match(const char *pattern, const char *string, resourcematch_extract_t **extract)
{
resourcematch_result_t ret;
resourcematch_extract_t *matches = NULL;
size_t idx = 0;
if (!pattern || !string)
return RESOURCEMATCH_ERROR;
if (extract) {
matches = allocate_extract(pattern);
if (!matches)
return RESOURCEMATCH_NOMATCH;
}
while (1) {
strip_common_prefix(&pattern, &string);
if (!*pattern && !*string) {
if (extract)
*extract = matches;
return RESOURCEMATCH_MATCH;
} else if (!*pattern || !*string) {
if (extract)
resourcematch_extract_free(matches);
return RESOURCEMATCH_NOMATCH;
}
if (*pattern != '%') {
if (extract)
resourcematch_extract_free(matches);
return RESOURCEMATCH_NOMATCH;
}
pattern++;
switch (*pattern) {
case '%':
if (*string == '%') {
string++;
} else {
if (extract)
resourcematch_extract_free(matches);
return RESOURCEMATCH_NOMATCH;
}
break;
#define _test_int(type,base) \
case (type): \
setup_group(matches, idx, *pattern); \
\
ret = match_lli(&string, matches, idx, (base)); \
if (ret != RESOURCEMATCH_MATCH) { \
if (extract) \
resourcematch_extract_free(matches); \
\
return ret; \
} \
idx++; \
break;
_test_int('i', 0);
_test_int('d', 10);
_test_int('x', 16);
_test_int('o', 8);
default:
if (extract)
resourcematch_extract_free(matches);
return RESOURCEMATCH_ERROR;
break;
}
pattern++;
}
}
void resourcematch_extract_free(resourcematch_extract_t *extract)
{
size_t i;
if (!extract)
return;
for (i = 0; i < extract->groups; i++) {
free(extract->group[i].raw);
}
free(extract->group);
free(extract);
}
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __RESOURCEMATCH_H__
#define __RESOURCEMATCH_H__
#include <sys/types.h>
typedef enum {
RESOURCEMATCH_ERROR,
RESOURCEMATCH_MATCH,
RESOURCEMATCH_NOMATCH
} resourcematch_result_t;
typedef struct {
char type;
char *raw;
union {
const char *string;
long long int lli;
} result;
} resourcematch_group_t;
typedef struct {
size_t groups;
resourcematch_group_t *group;
} resourcematch_extract_t;
resourcematch_result_t resourcematch_match(const char *pattern, const char *string, resourcematch_extract_t **extract);
void resourcematch_extract_free(resourcematch_extract_t *extract);
#endif
......@@ -102,7 +102,7 @@ source_t *source_reserve (const char *mount)
src->client_tree = avl_tree_new(_compare_clients, NULL);
src->pending_tree = avl_tree_new(_compare_clients, NULL);
src->history = playlist_new(4 /* DOCUMENT: default is max_tracks=4. */);
src->history = playlist_new(10 /* DOCUMENT: default is max_tracks=10. */);
/* make duplicates for strings or similar */
src->mount = strdup(mount);
......
......@@ -100,8 +100,8 @@ static mutex_t xsltlock;
/* Reference to the original xslt loader func */
static xsltDocLoaderFunc xslt_loader;
/* Admin path cache */
static xmlChar *admin_path = NULL;
/* Admin URI cache */
static xmlChar *admin_URI = NULL;
void xslt_initialize(void)
{
......@@ -115,20 +115,40 @@ void xslt_initialize(void)
}
void xslt_shutdown(void) {
int i;
for(i=0; i < CACHESIZE; i++) {
if(cache[i].filename)
free(cache[i].filename);
if(cache[i].stylesheet)
xsltFreeStylesheet(cache[i].stylesheet);
}
xslt_clear_cache();
thread_mutex_destroy (&xsltlock);
xmlCleanupParser();
xsltCleanupGlobals();
if (admin_path)
xmlFree(admin_path);
if (admin_URI)
xmlFree(admin_URI);
}
static void clear_cache_entry(size_t idx) {
free(cache[idx].filename);
if (cache[idx].stylesheet)
xsltFreeStylesheet(cache[idx].stylesheet);
cache[idx].filename = NULL;
}
void xslt_clear_cache(void)
{
size_t i;
ICECAST_LOG_DEBUG("Clearing stylesheet cache.");
thread_mutex_lock(&xsltlock);
for (i = 0; i < CACHESIZE; i++)
clear_cache_entry(i);
if (admin_URI) {
xmlFree(admin_URI);
admin_URI = NULL;
}
thread_mutex_unlock(&xsltlock);
}
static int evict_cache_entry(void) {
......@@ -141,8 +161,7 @@ static int evict_cache_entry(void) {
}
}
xsltFreeStylesheet(cache[oldest].stylesheet);
free(cache[oldest].filename);
clear_cache_entry(oldest);
return oldest;
}
......@@ -152,23 +171,23 @@ static xsltStylesheetPtr xslt_get_stylesheet(const char *fn) {
int empty = -1;
struct stat file;
if(stat(fn, &file)) {
ICECAST_LOG_DEBUG("Looking up stylesheet file \"%s\".", fn);
if (stat(fn, &file) != 0) {
ICECAST_LOG_WARN("Error checking for stylesheet file \"%s\": %s", fn,
strerror(errno));
return NULL;
}
for(i=0; i < CACHESIZE; i++) {
if(cache[i].filename)
{
for (i = 0; i < CACHESIZE; i++) {
if(cache[i].filename) {
#ifdef _WIN32
if(!stricmp(fn, cache[i].filename))
if(!stricmp(fn, cache[i].filename)) {
#else
if(!strcmp(fn, cache[i].filename))
if(!strcmp(fn, cache[i].filename)) {
#endif
{
if(file.st_mtime > cache[i].last_modified)
{
if(file.st_mtime > cache[i].last_modified) {
ICECAST_LOG_DEBUG("Source file newer than cached copy. Reloading slot %i", i);
xsltFreeStylesheet(cache[i].stylesheet);
cache[i].last_modified = file.st_mtime;
......@@ -178,20 +197,24 @@ static xsltStylesheetPtr xslt_get_stylesheet(const char *fn) {
ICECAST_LOG_DEBUG("Using cached sheet %i", i);
return cache[i].stylesheet;
}
}
else
} else {
empty = i;
}
}
if(empty>=0)
if (empty >= 0) {
i = empty;
else
ICECAST_LOG_DEBUG("Using empty slot %i", i);
} else {
i = evict_cache_entry();
ICECAST_LOG_DEBUG("Using evicted slot %i", i);
}
cache[i].last_modified = file.st_mtime;
cache[i].filename = strdup(fn);
cache[i].stylesheet = xsltParseStylesheetFile(XMLSTR(fn));
cache[i].cache_age = time(NULL);
return cache[i].stylesheet;
}
......@@ -203,7 +226,7 @@ static xmlDocPtr custom_loader(const xmlChar *URI,
xsltLoadType type)
{
xmlDocPtr ret;
xmlChar *rel_path, *fn, *final_URI = NULL;
xmlChar *rel_URI, *fn, *final_URI = NULL;
char *path_URI = NULL;
xsltStylesheet *c;
ice_config_t *config;
......@@ -230,44 +253,43 @@ static xmlDocPtr custom_loader(const xmlChar *URI,
break;
/* Construct the right path */
rel_path = xmlBuildRelativeURI(URI, c->doc->URL);
if (rel_path != NULL && admin_path != NULL) {
fn = xmlBuildURI(rel_path, admin_path);
rel_URI = xmlBuildRelativeURI(URI, c->doc->URL);
if (rel_URI != NULL && admin_URI != NULL) {
fn = xmlBuildURI(rel_URI, admin_URI);
final_URI = fn;
xmlFree(rel_path);
xmlFree(rel_URI);
}
/* Fail if there was an error constructing the path */
if (final_URI == NULL) {
if (rel_path)
xmlFree(rel_path);
if (rel_URI)
xmlFree(rel_URI);
return NULL;
}
break;
/* In case a top stylesheet is loaded */
case XSLT_LOAD_START:
config = config_get_config();
/* Admin path is cached, so that we don't need to get it from
* the config every time we load a xsl include.
* Whenever a new top stylesheet is loaded, we check here
* if the path in the config has changed and adjust it, if needed.
*/
if (admin_path != NULL &&
strcmp(config->adminroot_dir, (char *)admin_path) != 0) {
xmlFree(admin_path);
admin_path = NULL;
/* Check if the admin URI is already cached */
if (admin_URI != NULL) {
break;
}
/* Do we need to load the admin path? */
if (!admin_path) {
config = config_get_config();
/* Append path separator to path */
size_t len = strlen(config->adminroot_dir);
xmlChar* admin_path = xmlMalloc(len+2);
xmlStrPrintf(admin_path, len+2, XMLSTR("%s/"), XMLSTR(config->adminroot_dir));
admin_path = xmlMalloc(len+2);
if (!admin_path)
return NULL;
/* Convert admin path to URI */
admin_URI = xmlPathToURI(admin_path);
xmlFree(admin_path);
/* Copy over admin path and add a tailing slash. */
xmlStrPrintf(admin_path, len+2, XMLSTR("%s/"), XMLSTR(config->adminroot_dir));
}
if (!admin_URI) {
return NULL;
} else {
ICECAST_LOG_DEBUG("Loaded and cached admin_URI \"%s\"", admin_URI);
}
config_release_config();
break;
......@@ -278,9 +300,11 @@ static xmlDocPtr custom_loader(const xmlChar *URI,
/* Get the actual xmlDoc */
if (final_URI) {
ICECAST_LOG_DEBUG("Calling xslt_loader() for \"%s\" (was: \"%s\").", final_URI, URI);
ret = xslt_loader(final_URI, dict, options, ctxt, type);
xmlFree(final_URI);
} else {
ICECAST_LOG_DEBUG("Calling xslt_loader() for \"%s\".", URI);
ret = xslt_loader(URI, dict, options, ctxt, type);
}
return ret;
......
......@@ -19,4 +19,5 @@
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, int status);
void xslt_initialize(void);
void xslt_shutdown(void);
void xslt_clear_cache(void);