diff --git a/src/Makefile.am b/src/Makefile.am index e3a3d9d8..fae29c14 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,7 @@ noinst_HEADERS = \ matchfile.h \ tls.h \ refobject.h \ + module.h \ event.h \ event_log.h \ event_exec.h \ @@ -70,6 +71,7 @@ icecast_SOURCES = \ matchfile.c \ tls.c \ refobject.c \ + module.c \ format.c \ format_ogg.c \ format_mp3.c \ diff --git a/src/icecasttypes.h b/src/icecasttypes.h index 0474e0f3..36b198a4 100644 --- a/src/icecasttypes.h +++ b/src/icecasttypes.h @@ -92,6 +92,12 @@ typedef enum { typedef struct _relay_server relay_server; +/* ---[ module.[ch] ]--- */ + +typedef struct module_tag module_t; + +typedef struct module_container_tag module_container_t; + /* ---[ refobject.[ch] ]--- */ typedef struct refobject_base_tag refobject_base_t; @@ -99,6 +105,8 @@ typedef struct refobject_base_tag refobject_base_t; #ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION typedef union __attribute__ ((__transparent_union__)) { refobject_base_t *refobject_base; + module_t *module; + module_container_t *module_container; } refobject_t; #else typedef void * refobject_t; diff --git a/src/module.c b/src/module.c new file mode 100644 index 00000000..3dc524b7 --- /dev/null +++ b/src/module.c @@ -0,0 +1,160 @@ +/* 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 , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "common/thread/thread.h" +#include "common/avl/avl.h" + +#include "refobject.h" +#include "module.h" + +struct module_tag { + refobject_base_t __base; + mutex_t lock; + const module_client_handler_t *client_handlers; + size_t client_handlers_len; +}; + + +struct module_container_tag { + refobject_base_t __base; + mutex_t lock; + avl_tree *module; +}; + +static int compare_refobject_t_name(void *arg, void *a, void *b) +{ + return strcmp(refobject_get_name(a), refobject_get_name(b)); +} + +static void __module_container_free(refobject_t self, void **userdata) +{ + module_container_t *cont = REFOBJECT_TO_TYPE(self, module_container_t *); + thread_mutex_destroy(&(cont->lock)); + avl_tree_free(cont->module, (avl_free_key_fun_type)refobject_unref); +} + +module_container_t * module_container_new(void) +{ + module_container_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(module_container_t), __module_container_free, NULL, NULL, NULL), module_container_t *); + + if (!ret) + return NULL; + + thread_mutex_create(&(ret->lock)); + + ret->module = avl_tree_new(compare_refobject_t_name, NULL); + + return ret; +} + +int module_container_add_module(module_container_t *self, module_t *module) +{ + if (!self) + return -1; + + thread_mutex_lock(&(self->lock)); + avl_insert(self->module, module); + thread_mutex_unlock(&(self->lock)); + + return 0; +} + +int module_container_delete_module(module_container_t *self, const char *name) +{ + module_t *module; + + if (!self || !name) + return -1; + + module = module_container_get_module(self, name); + if (!module) + return -1; + + thread_mutex_lock(&(self->lock)); + avl_delete(self->module, module, (avl_free_key_fun_type)refobject_unref); + thread_mutex_unlock(&(self->lock)); + + refobject_unref(module); + + return 0; +} + +module_t * module_container_get_module(module_container_t *self, const char *name) +{ + refobject_t search; + module_t *ret; + + if (!self || !name) + return NULL; + + search = refobject_new(sizeof(refobject_base_t), NULL, NULL, name, NULL); + + if (avl_get_by_key(self->module, REFOBJECT_TO_TYPE(search, void *), (void**)&ret) != 0) { + ret = NULL; + } + + refobject_unref(search); + + return ret; +} + +static void __module_free(refobject_t self, void **userdata) +{ + module_t *mod = REFOBJECT_TO_TYPE(self, module_t *); + thread_mutex_destroy(&(mod->lock)); +} + +module_t * module_new(const char *name, module_setup_handler_t newcb, module_setup_handler_t freecb, void *userdata) +{ + module_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(module_t), __module_free, NULL, name, NULL), module_t *); + + if (!ret) + return NULL; + + thread_mutex_create(&(ret->lock)); + + return ret; +} + +const module_client_handler_t * module_get_client_handler(module_t *self, const char *name) +{ + size_t i; + + if (!self || !name) + return NULL; + + thread_mutex_lock(&(self->lock)); + for (i = 0; i < self->client_handlers_len; i++) { + if (self->client_handlers[i].name && strcmp(self->client_handlers[i].name, name) == 0) { + thread_mutex_unlock(&(self->lock)); + return &(self->client_handlers[i]); + } + } + thread_mutex_unlock(&(self->lock)); + + return NULL; +} + +int module_add_client_handler(module_t *self, const module_client_handler_t *handlers, size_t len) +{ + if (!self) + return -1; + + thread_mutex_lock(&(self->lock)); + self->client_handlers = handlers; + self->client_handlers_len = len; + thread_mutex_unlock(&(self->lock)); + + return 0; +} diff --git a/src/module.h b/src/module.h new file mode 100644 index 00000000..8d2ad781 --- /dev/null +++ b/src/module.h @@ -0,0 +1,33 @@ +/* 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 , + */ + +#ifndef __MODULE_H__ +#define __MODULE_H__ + +#include "icecasttypes.h" + +typedef void (*module_client_handler_function_t)(module_t *self, client_t *client, const char *uri); +typedef int (*module_setup_handler_t)(module_t *self, void **userdata); + +typedef struct { + const char *name; + module_client_handler_function_t cb; +} module_client_handler_t; + +module_container_t * module_container_new(void); +int module_container_add_module(module_container_t *self, module_t *module); +int module_container_delete_module(module_container_t *self, const char *name); +module_t * module_container_get_module(module_container_t *self, const char *name); + +module_t * module_new(const char *name, module_setup_handler_t newcb, module_setup_handler_t freecb, void *userdata); + +/* Note: Those functions are not really thread safe as (module_client_handler_t) is not thread safe. This is by design. */ +const module_client_handler_t * module_get_client_handler(module_t *self, const char *name); +int module_add_client_handler(module_t *self, const module_client_handler_t *handlers, size_t len); + +#endif