[angel] Add basic module/plugin support
* renamed some module functions
This commit is contained in:
parent
6a9cea1404
commit
48bf0071e4
|
@ -21,7 +21,8 @@ typedef struct instance instance;
|
|||
#include <lighttpd/angel_value.h>
|
||||
#include <lighttpd/angel_data.h>
|
||||
#include <lighttpd/angel_connection.h>
|
||||
#include <lighttpd/angel_server.h>
|
||||
#include <lighttpd/angel_log.h>
|
||||
#include <lighttpd/angel_plugin.h>
|
||||
#include <lighttpd/angel_server.h>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,6 @@ typedef enum {
|
|||
ANGEL_CONFIG_PARSER_ERROR_PARSE, /* parse error */
|
||||
} AngelConfigParserError;
|
||||
|
||||
LI_API gboolean angel_config_parse_file(const gchar *filename, GError **err);
|
||||
LI_API gboolean angel_config_parse_file(server *srv, const gchar *filename, GError **err);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef _LIGHTTPD_ANGEL_LOG_H_
|
||||
#define _LIGHTTPD_ANGEL_LOG_H_
|
||||
|
||||
#ifndef _LIGHTTPD_ANGEL_BASE_H_
|
||||
#error Please include <lighttpd/angel_base.h> instead of this file
|
||||
#endif
|
||||
|
||||
/* #include <lighttpd/valgrind/valgrind.h> */
|
||||
|
||||
#define REMOVE_PATH_FROM_FILE 1
|
||||
#if REMOVE_PATH_FROM_FILE
|
||||
LI_API const char *remove_path(const char *path);
|
||||
#define REMOVE_PATH(file) remove_path(file)
|
||||
#else
|
||||
#define REMOVE_PATH(file) file
|
||||
#endif
|
||||
|
||||
#define SEGFAULT(srv, fmt, ...) \
|
||||
do { \
|
||||
log_write_(srv, LOG_LEVEL_ABORT, LOG_FLAG_TIMESTAMP, "(crashing) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__); \
|
||||
/* VALGRIND_PRINTF_BACKTRACE(fmt, __VA_ARGS__); */\
|
||||
abort();\
|
||||
} while(0)
|
||||
|
||||
#define ERROR(srv, fmt, ...) \
|
||||
log_write(srv, LOG_LEVEL_ERROR, LOG_FLAG_TIMESTAMP, "error (%s:%d): "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define WARNING(srv, fmt, ...) \
|
||||
log_write(srv, LOG_LEVEL_WARNING, LOG_FLAG_TIMESTAMP, "warning (%s:%d): "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define INFO(srv, fmt, ...) \
|
||||
log_write(srv, LOG_LEVEL_INFO, LOG_FLAG_TIMESTAMP, "info (%s:%d): "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define DEBUG(srv, fmt, ...) \
|
||||
log_write(srv, LOG_LEVEL_DEBUG, LOG_FLAG_TIMESTAMP, "debug (%s:%d): "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
/* log messages from lighty always as ERROR */
|
||||
#define INSTANCE(srv, inst, msg) \
|
||||
log_write(srv, LOG_LEVEL_ERROR, LOG_FLAG_NONE, "lighttpd[%d]: %s", (int) inst->pid, msg)
|
||||
|
||||
typedef enum {
|
||||
LOG_LEVEL_DEBUG,
|
||||
LOG_LEVEL_INFO,
|
||||
LOG_LEVEL_WARNING,
|
||||
LOG_LEVEL_ERROR,
|
||||
LOG_LEVEL_ABORT
|
||||
} log_level_t;
|
||||
|
||||
#define LOG_LEVEL_COUNT (LOG_LEVEL_ABORT+1)
|
||||
|
||||
typedef enum {
|
||||
LOG_TYPE_STDERR,
|
||||
LOG_TYPE_FILE,
|
||||
LOG_TYPE_PIPE,
|
||||
LOG_TYPE_SYSLOG,
|
||||
LOG_TYPE_NONE
|
||||
} log_type_t;
|
||||
|
||||
#define LOG_FLAG_NONE (0x0) /* default flag */
|
||||
#define LOG_FLAG_TIMESTAMP (0x1) /* prepend a timestamp to the log message */
|
||||
|
||||
struct log_t;
|
||||
typedef struct log_t log_t;
|
||||
|
||||
struct log_t {
|
||||
log_type_t type;
|
||||
gboolean levels[LOG_LEVEL_COUNT];
|
||||
GString *path;
|
||||
gint fd;
|
||||
|
||||
time_t last_ts;
|
||||
GString *ts_cache;
|
||||
|
||||
GString *log_line;
|
||||
};
|
||||
|
||||
void log_init(server *srv);
|
||||
void log_clean(server *srv);
|
||||
|
||||
LI_API void log_write(server *srv, log_level_t log_level, guint flags, const gchar *fmt, ...) G_GNUC_PRINTF(4, 5);
|
||||
|
||||
#endif
|
|
@ -5,7 +5,75 @@
|
|||
#error Please include <lighttpd/angel_base.h> instead of this file
|
||||
#endif
|
||||
|
||||
typedef struct plugin_item plugin_item;
|
||||
typedef struct plugin_item_option plugin_item_option;
|
||||
typedef struct plugin plugin;
|
||||
typedef struct Plugins Plugins;
|
||||
|
||||
LI_API gboolean plugins_handle_item(server *srv, value *hash);
|
||||
typedef gboolean (*PluginInit) (server *srv, plugin *p);
|
||||
typedef void (*PluginFree) (server *srv, plugin *p);
|
||||
|
||||
typedef void (*PluginCleanConfig) (server *srv, plugin *p);
|
||||
typedef gboolean (*PluginCheckConfig) (server *srv, plugin *p);
|
||||
typedef void (*PluginActivateConfig)(server *srv, plugin *p);
|
||||
typedef void (*PluginParseItem) (server *srv, plugin *p, value **options);
|
||||
|
||||
typedef enum {
|
||||
PLUGIN_ITEM_OPTION_MANDATORY = 1
|
||||
} plugin_item_option_flags;
|
||||
|
||||
struct plugin_item_option {
|
||||
const gchar *name; /**< name of the option */
|
||||
value_type type; /**< type of the option; may be VALUE_NONE to accept anything */
|
||||
plugin_item_option_flags flags; /**< flags of the option */
|
||||
};
|
||||
|
||||
struct plugin_item {
|
||||
const gchar *name;
|
||||
PluginParseItem handle_parse_item;
|
||||
|
||||
const plugin_item_option options[];
|
||||
};
|
||||
|
||||
struct plugin {
|
||||
size_t version;
|
||||
const gchar *name; /**< name of the plugin */
|
||||
|
||||
gpointer data; /**< private plugin data */
|
||||
|
||||
const plugin_item *items;
|
||||
|
||||
PluginInit plugin_init_marker; /**< identify plugin; PluginInit must be unique per plugin */
|
||||
PluginFree handle_free; /**< called before plugin is unloaded */
|
||||
|
||||
PluginCleanConfig handle_clean_config; /**< called before the reloading of the config is started or after the reloading failed */
|
||||
PluginCheckConfig handle_check_config; /**< called before activating a config to ensure everything works */
|
||||
PluginActivateConfig handle_activate_config; /**< called to activate a config after successful loading it. this cannot fail */
|
||||
};
|
||||
|
||||
struct Plugins {
|
||||
GString *config_filename;
|
||||
|
||||
GHashTable *items, *load_items; /**< gchar* -> server_item */
|
||||
|
||||
struct modules *modules;
|
||||
|
||||
GHashTable *module_refs, *load_module_refs; /** gchar* -> server_module */
|
||||
|
||||
GPtrArray *plugins, *load_plugins; /* plugin* */
|
||||
};
|
||||
|
||||
void plugins_init(server *srv, const gchar *module_dir);
|
||||
void plugins_clear(server *srv);
|
||||
|
||||
void plugins_config_clean(server *srv);
|
||||
gboolean plugins_config_load(server *srv, const gchar *filename);
|
||||
|
||||
gboolean plugins_handle_item(server *srv, GString *itemname, value *hash);
|
||||
|
||||
/* "core" is a reserved module name for interal use */
|
||||
gboolean plugins_load_module(server *srv, const gchar *name);
|
||||
/* Needed by modules to register their plugin(s) */
|
||||
LI_API plugin *angel_plugin_register(server *srv, module *mod, const gchar *name, PluginInit init);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _LIGHTTPD_ANGEL_PLUGIN_CORE_H_
|
||||
#define _LIGHTTPD_ANGEL_PLUGIN_CORE_H_
|
||||
|
||||
#include <lighttpd/angel_base.h>
|
||||
|
||||
gboolean plugin_core_init(server *srv);
|
||||
|
||||
#endif
|
|
@ -22,12 +22,9 @@ struct server {
|
|||
sig_w_TERM,
|
||||
sig_w_PIPE;
|
||||
|
||||
struct modules *modules;
|
||||
Plugins plugins;
|
||||
|
||||
GHashTable *plugins; /**< const gchar* => (plugin*) */
|
||||
struct plugin *core_plugin;
|
||||
|
||||
ev_tstamp started;
|
||||
log_t log;
|
||||
};
|
||||
|
||||
LI_API server* server_new(const gchar *module_dir);
|
||||
|
|
|
@ -32,7 +32,8 @@ LI_API const char *remove_path(const char *path);
|
|||
log_write_(srv, vr, LOG_LEVEL_INFO, LOG_FLAG_TIMESTAMP, "(info) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define _DEBUG(srv, vr, fmt, ...) \
|
||||
log_write_(srv, vr, LOG_LEVEL_INFO, LOG_FLAG_TIMESTAMP, "(debug) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
log_write_(srv, vr, LOG_LEVEL_DEBUG, LOG_FLAG_TIMESTAMP, "(debug) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define _BACKEND(srv, vr, fmt, ...) \
|
||||
log_write_(srv, vr, LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP, "(backend) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
#define _BACKEND_LINES(srv, vr, txt, fmt, ...) \
|
||||
|
|
|
@ -52,8 +52,8 @@ struct modules {
|
|||
guint8 sizeof_off_t; /** holds the value of sizeof(off_t) to check if loaded module was compiled with the same flags */
|
||||
};
|
||||
|
||||
LI_API modules* modules_init(gpointer main, const gchar *module_dir);
|
||||
LI_API void modules_cleanup(modules *mods);
|
||||
LI_API modules* modules_new(gpointer main, const gchar *module_dir);
|
||||
LI_API void modules_free(modules *mods);
|
||||
|
||||
/** Loads a module if not loaded yet and returns the module struct for it (after increasing refcount)
|
||||
* returns NULL if it couldn't load the module.
|
||||
|
|
|
@ -359,11 +359,17 @@ ADD_TARGET_PROPERTIES(lighttpd LINK_FLAGS ${COMMON_LDFLAGS})
|
|||
ADD_TARGET_PROPERTIES(lighttpd COMPILE_FLAGS ${COMMON_CFLAGS})
|
||||
|
||||
ADD_EXECUTABLE(lighttpd-angel
|
||||
angel_data.c
|
||||
angel_main.c
|
||||
angel_value.c
|
||||
angel_plugin.c
|
||||
angel_config_parser.c
|
||||
angel_data.c
|
||||
angel_log.c
|
||||
angel_main.c
|
||||
angel_plugin.c
|
||||
angel_plugin_core.c
|
||||
angel_server.c
|
||||
angel_value.c
|
||||
condition_parsers.c
|
||||
module.c
|
||||
utils.c
|
||||
)
|
||||
|
||||
ADD_TARGET_PROPERTIES(lighttpd-angel LINK_FLAGS "${LUA_LDFLAGS} ${EV_LDFLAGS} ${GMODULE_LDFLAGS} ${WARN_FLAGS}")
|
||||
|
|
|
@ -102,9 +102,7 @@ static gchar *format_char(pcontext *ctx, gchar c) {
|
|||
}
|
||||
|
||||
action enditem {
|
||||
GString *tmp = value_to_string(ctx->itemvalue);
|
||||
g_printerr("Item '%s': %s\n", ctx->itemname->str, tmp->str);
|
||||
g_string_free(tmp, TRUE);
|
||||
plugins_handle_item(srv, ctx->itemname, ctx->itemvalue);
|
||||
g_string_free(ctx->itemname, TRUE);
|
||||
ctx->itemname = NULL;
|
||||
value_free(ctx->itemvalue);
|
||||
|
@ -422,7 +420,7 @@ static gboolean angel_config_parser_finalize(pcontext *ctx, filecontext *fctx, G
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean angel_config_parse_data(pcontext *ctx, filecontext *fctx, gchar *data, gsize len, GError **err) {
|
||||
static gboolean angel_config_parse_data(server *srv, pcontext *ctx, filecontext *fctx, gchar *data, gsize len, GError **err) {
|
||||
gchar *p = data, *pe = p+len, *eof = NULL, *linestart = p, *tokenstart = NULL;
|
||||
if (ctx->readingtoken) tokenstart = p;
|
||||
|
||||
|
@ -443,7 +441,7 @@ static gboolean angel_config_parse_data(pcontext *ctx, filecontext *fctx, gchar
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean angel_config_parse_file(const gchar *filename, GError **err) {
|
||||
gboolean angel_config_parse_file(server *srv, const gchar *filename, GError **err) {
|
||||
char *data = NULL;
|
||||
gsize len = 0;
|
||||
filecontext sfctx, *fctx = &sfctx;
|
||||
|
@ -456,7 +454,7 @@ gboolean angel_config_parse_file(const gchar *filename, GError **err) {
|
|||
sfctx.filename = filename;
|
||||
sfctx.line = 1;
|
||||
sfctx.column = 1;
|
||||
if (!angel_config_parse_data(ctx, fctx, data, len, err)) goto error;
|
||||
if (!angel_config_parse_data(srv, ctx, fctx, data, len, err)) goto error;
|
||||
if (!angel_config_parser_finalize(ctx, fctx, err)) goto error;
|
||||
|
||||
if (data) g_free(data);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
#include <lighttpd/angel_base.h>
|
||||
|
||||
#if REMOVE_PATH_FROM_FILE
|
||||
const char *remove_path(const char *path) {
|
||||
char *p = strrchr(path, DIR_SEPERATOR);
|
||||
if (NULL != p && *(p) != '\0') {
|
||||
return (p + 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
|
||||
void log_init(server *srv) {
|
||||
srv->log.type = LOG_TYPE_STDERR;
|
||||
|
||||
srv->log.levels[LOG_LEVEL_ABORT] = TRUE;
|
||||
srv->log.levels[LOG_LEVEL_ERROR] = TRUE;
|
||||
srv->log.levels[LOG_LEVEL_WARNING] = TRUE;
|
||||
|
||||
srv->log.fd = -1;
|
||||
srv->log.ts_cache = g_string_sized_new(0);
|
||||
srv->log.log_line = g_string_sized_new(0);
|
||||
}
|
||||
|
||||
void log_clean(server *srv) {
|
||||
g_string_free(srv->log.ts_cache, TRUE);
|
||||
g_string_free(srv->log.log_line, TRUE);
|
||||
}
|
||||
|
||||
void log_write(server *srv, log_level_t log_level, guint flags, const gchar *fmt, ...) {
|
||||
va_list ap;
|
||||
GString *log_line = srv->log.log_line;
|
||||
|
||||
if (!srv->log.levels[log_level]) return;
|
||||
|
||||
g_string_truncate(log_line, 0);
|
||||
|
||||
/* for normal error messages, we prepend a timestamp */
|
||||
if (flags & LOG_FLAG_TIMESTAMP) {
|
||||
GString *log_ts = srv->log.ts_cache;
|
||||
time_t cur_ts;
|
||||
|
||||
cur_ts = (time_t)ev_now(srv->loop);
|
||||
|
||||
if (cur_ts != srv->log.last_ts) {
|
||||
gsize s;
|
||||
g_string_set_size(log_ts, 255);
|
||||
s = strftime(log_ts->str, log_ts->allocated_len, "%Y-%m-%d %H:%M:%S %Z: ", localtime(&cur_ts));
|
||||
|
||||
g_string_set_size(log_ts, s);
|
||||
|
||||
srv->log.last_ts = cur_ts;
|
||||
}
|
||||
|
||||
g_string_append_len(log_line, GSTR_LEN(log_ts));
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
g_string_append_vprintf(log_line, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
g_string_append_len(log_line, CONST_STR_LEN("\n"));
|
||||
|
||||
fprintf(stderr, "%s", log_line->str);
|
||||
}
|
|
@ -14,6 +14,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
gboolean res;
|
||||
int result = 0;
|
||||
server* srv = NULL;
|
||||
|
||||
GOptionEntry entries[] = {
|
||||
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &config_path, "filename/path of the config", "PATH" },
|
||||
|
@ -50,9 +51,9 @@ int main(int argc, char *argv[]) {
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!angel_config_parse_file(config_path, &error)) {
|
||||
g_printerr("lighttpd-angel: failed to parse config file: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
srv = server_new(module_dir);
|
||||
|
||||
if (!plugins_config_load(srv, config_path)) {
|
||||
result = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -60,6 +61,7 @@ int main(int argc, char *argv[]) {
|
|||
g_printerr("lighttpd-angel: Parsed config file\n");
|
||||
|
||||
cleanup:
|
||||
if (srv) server_free(srv);
|
||||
if (config_path) g_free((gchar*) config_path);
|
||||
if (module_dir != def_module_dir) g_free((gchar*) module_dir);
|
||||
|
||||
|
|
|
@ -0,0 +1,351 @@
|
|||
|
||||
#include <lighttpd/angel_base.h>
|
||||
#include <lighttpd/angel_config_parser.h>
|
||||
#include <lighttpd/angel_plugin_core.h>
|
||||
|
||||
/* internal structures */
|
||||
|
||||
typedef struct server_item server_item;
|
||||
struct server_item {
|
||||
plugin *p;
|
||||
guint option_count;
|
||||
const plugin_item *p_item;
|
||||
};
|
||||
|
||||
typedef struct server_module server_module;
|
||||
struct server_module {
|
||||
guint refcount;
|
||||
gchar *name;
|
||||
server *srv;
|
||||
module *mod;
|
||||
GPtrArray *plugins; /* plugin* */
|
||||
};
|
||||
|
||||
static void _server_item_free(gpointer p) {
|
||||
g_slice_free(server_item, p);
|
||||
}
|
||||
|
||||
static server_item* server_item_new(plugin *p, const plugin_item *p_item) {
|
||||
server_item *si = g_slice_new(server_item);
|
||||
const plugin_item_option *pio;
|
||||
guint cnt;
|
||||
for (pio = p_item->options, cnt = 0; pio->name; pio++, cnt++) ;
|
||||
si->p = p;
|
||||
si->option_count = cnt;
|
||||
si->p_item = p_item;
|
||||
return si;
|
||||
}
|
||||
|
||||
static void plugin_free(server *srv, plugin *p) {
|
||||
if (p->handle_free) p->handle_free(srv, p);
|
||||
g_slice_free(plugin, p);
|
||||
}
|
||||
|
||||
static plugin* plugin_new(const char *name) {
|
||||
plugin *p = g_slice_new0(plugin);
|
||||
p->name = name;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void _server_module_release(gpointer d) {
|
||||
server_module *sm = d;
|
||||
guint i;
|
||||
|
||||
g_assert(sm->refcount > 0);
|
||||
if (0 != --sm->refcount) return;
|
||||
|
||||
for (i = sm->plugins->len; i-- > 0; ) {
|
||||
plugin *p = g_ptr_array_index(sm->plugins, i);
|
||||
plugin_free(sm->srv, p);
|
||||
}
|
||||
g_ptr_array_free(sm->plugins, TRUE);
|
||||
if (sm->mod) module_release(sm->srv->plugins.modules, sm->mod);
|
||||
g_free(sm->name);
|
||||
g_slice_free(server_module, sm);
|
||||
}
|
||||
|
||||
static void server_module_acquire(server_module *sm) {
|
||||
g_assert(sm->refcount > 0);
|
||||
sm->refcount++;
|
||||
}
|
||||
|
||||
static server_module* server_module_new(server *srv, const gchar *name) { /* module is set later */
|
||||
server_module *sm = g_slice_new0(server_module);
|
||||
sm->refcount = 1;
|
||||
sm->srv = srv;
|
||||
sm->plugins = g_ptr_array_new();
|
||||
sm->name = g_strdup(name);
|
||||
return sm;
|
||||
}
|
||||
|
||||
void plugins_init(server *srv, const gchar *module_dir) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
|
||||
ps->modules = modules_new(srv, module_dir);
|
||||
|
||||
ps->items = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, _server_item_free);
|
||||
ps->load_items = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, _server_item_free);
|
||||
|
||||
ps->module_refs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, _server_module_release);
|
||||
ps->load_module_refs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, _server_module_release);
|
||||
|
||||
ps->plugins = g_ptr_array_new();
|
||||
ps->load_plugins = g_ptr_array_new();
|
||||
}
|
||||
|
||||
void plugins_clear(server *srv) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
|
||||
plugins_config_clean(srv);
|
||||
|
||||
g_hash_table_destroy(ps->items);
|
||||
g_hash_table_destroy(ps->load_items);
|
||||
|
||||
g_hash_table_destroy(ps->module_refs);
|
||||
g_hash_table_destroy(ps->load_module_refs);
|
||||
|
||||
g_ptr_array_free(ps->plugins, TRUE);
|
||||
g_ptr_array_free(ps->load_plugins, TRUE);
|
||||
|
||||
if (ps->config_filename) g_string_free(ps->config_filename, TRUE);
|
||||
|
||||
modules_free(ps->modules);
|
||||
}
|
||||
|
||||
void plugins_config_clean(server *srv) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
guint i;
|
||||
|
||||
for (i = ps->load_plugins->len; i-- > 0; ) {
|
||||
plugin *p = g_ptr_array_index(ps->load_plugins, i);
|
||||
if (p->handle_clean_config) p->handle_clean_config(srv, p);
|
||||
}
|
||||
|
||||
g_hash_table_remove_all(ps->load_items);
|
||||
g_hash_table_remove_all(ps->load_module_refs);
|
||||
g_ptr_array_set_size(ps->load_plugins, 0);
|
||||
}
|
||||
|
||||
gboolean plugins_config_load(server *srv, const gchar *filename) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
GError *error = NULL;
|
||||
guint i;
|
||||
|
||||
if (!angel_config_parse_file(srv, filename, &error)) {
|
||||
ERROR(srv, "failed to parse config file: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
plugins_config_clean(srv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* check new config */
|
||||
for (i = ps->plugins->len; i-- > 0; ) {
|
||||
plugin *p = g_ptr_array_index(ps->load_plugins, i);
|
||||
if (p->handle_check_config) {
|
||||
if (!p->handle_check_config(srv, p)) {
|
||||
plugins_config_clean(srv);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* activate new config */
|
||||
for (i = ps->plugins->len; i-- > 0; ) {
|
||||
plugin *p = g_ptr_array_index(ps->load_plugins, i);
|
||||
if (p->handle_activate_config) {
|
||||
p->handle_activate_config(srv, p);
|
||||
}
|
||||
}
|
||||
|
||||
{ /* swap the arrays */
|
||||
GPtrArray *tmp = ps->load_plugins; ps->load_plugins = ps->plugins; ps->plugins = tmp;
|
||||
}
|
||||
{ /* swap the hash tables */
|
||||
GHashTable *tmp;
|
||||
tmp = ps->load_items; ps->load_items = ps->items; ps->items = tmp;
|
||||
tmp = ps->load_module_refs; ps->load_module_refs = ps->module_refs; ps->module_refs = tmp;
|
||||
}
|
||||
g_hash_table_remove_all(ps->load_items);
|
||||
g_hash_table_remove_all(ps->load_module_refs);
|
||||
g_ptr_array_set_size(ps->load_plugins, 0);
|
||||
|
||||
if (!ps->config_filename) {
|
||||
ps->config_filename = g_string_new(filename);
|
||||
} else {
|
||||
g_string_assign(ps->config_filename, filename);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean plugins_handle_item(server *srv, GString *itemname, value *hash) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
server_item *si;
|
||||
|
||||
#if 1
|
||||
/* debug items */
|
||||
{
|
||||
GString *tmp = value_to_string(hash);
|
||||
ERROR(srv, "Item '%s': %s\n", itemname->str, tmp->str);
|
||||
g_string_free(tmp, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
si = g_hash_table_lookup(ps->load_items, itemname->str);
|
||||
if (!si) {
|
||||
WARNING(srv, "Unknown item '%s' - perhaps you forgot to load the module? (ignored)", itemname->str);
|
||||
} else {
|
||||
value **optlist = g_slice_alloc0(sizeof(value*) * si->option_count);
|
||||
GHashTableIter opti;
|
||||
gpointer k, v;
|
||||
guint i;
|
||||
gboolean valid = TRUE;
|
||||
|
||||
/* find options and assign them by id */
|
||||
g_hash_table_iter_init(&opti, hash->data.hash);
|
||||
while (g_hash_table_iter_next(&opti, &k, &v)) {
|
||||
const gchar *optkey = ((GString*) k)->str;
|
||||
for (i = 0; i < si->option_count; i++) {
|
||||
if (0 == g_strcmp0(si->p_item->options[i].name, optkey)) break;
|
||||
}
|
||||
if (i == si->option_count) {
|
||||
WARNING(srv, "Unknown option '%s' in item '%s' (ignored)", optkey, itemname->str);
|
||||
} else {
|
||||
optlist[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
/* validate options */
|
||||
for (i = 0; i < si->option_count; i++) {
|
||||
const plugin_item_option *pi = &si->p_item->options[i];
|
||||
if (0 != (pi->flags & PLUGIN_ITEM_OPTION_MANDATORY)) {
|
||||
if (!optlist[i]) {
|
||||
ERROR(srv, "Missing mandatory option '%s' in item '%s'", pi->name, itemname->str);
|
||||
valid = FALSE;
|
||||
}
|
||||
}
|
||||
if (pi->type != VALUE_NONE && optlist[i] && optlist[i]->type != pi->type) {
|
||||
/* TODO: convert from string if possible */
|
||||
ERROR(srv, "Invalid value type of option '%s' in item '%s', got '%s' but expected '%s'",
|
||||
pi->name, itemname->str, value_type_string(optlist[i]->type), value_type_string(pi->type));
|
||||
valid = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
g_assert(si->p_item->handle_parse_item);
|
||||
si->p_item->handle_parse_item(srv, si->p, optlist);
|
||||
}
|
||||
|
||||
g_slice_free1(sizeof(value*) * si->option_count, optlist);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean plugins_activate_module(server *srv, server_module *sm) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
plugin *p;
|
||||
const plugin_item *pi;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < sm->plugins->len; i++) {
|
||||
p = g_ptr_array_index(sm->plugins, i);
|
||||
g_ptr_array_add(ps->load_plugins, p);
|
||||
if (!p->items) continue;
|
||||
|
||||
for (pi = p->items; pi->name; pi++) {
|
||||
server_item *si;
|
||||
if (NULL != (si = g_hash_table_lookup(ps->load_items, pi->name))) {
|
||||
ERROR(srv, "Plugin item name conflict: cannot load '%s' for plugin '%s' (already provided by plugin '%s')",
|
||||
pi->name, p->name, si->p->name);
|
||||
goto item_collission;
|
||||
} else {
|
||||
si = server_item_new(p, pi);
|
||||
g_hash_table_insert(ps->load_items, (gpointer) pi->name, si);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
item_collission:
|
||||
/* removed added items and plugins */
|
||||
for ( ; pi-- != p->items; ) {
|
||||
g_hash_table_remove(ps->load_items, pi->name);
|
||||
}
|
||||
|
||||
g_ptr_array_set_size(ps->load_plugins, ps->load_plugins->len - i+1);
|
||||
|
||||
for ( ; i-- > 0; ) {
|
||||
p = g_ptr_array_index(sm->plugins, i);
|
||||
if (!p->items) continue;
|
||||
|
||||
for (pi = p->items; pi->name; pi++) {
|
||||
g_hash_table_remove(ps->load_items, pi->name);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean plugins_load_module(server *srv, const gchar *name) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
server_module *sm;
|
||||
const gchar* modname = name ? name : "core";
|
||||
|
||||
sm = g_hash_table_lookup(ps->load_module_refs, modname);
|
||||
if (sm) return TRUE; /* already loaded */
|
||||
sm = g_hash_table_lookup(ps->module_refs, modname);
|
||||
if (sm) { /* loaded in previous config */
|
||||
server_module_acquire(sm);
|
||||
g_hash_table_insert(ps->load_module_refs, sm->name, sm);
|
||||
} else { /* not loaded yet */
|
||||
module *mod;
|
||||
sm = server_module_new(srv, modname);
|
||||
g_hash_table_insert(ps->load_module_refs, sm->name, sm);
|
||||
if (name) {
|
||||
mod = module_load(ps->modules, name);
|
||||
|
||||
if (!mod) {
|
||||
_server_module_release(sm);
|
||||
return FALSE;
|
||||
}
|
||||
sm->mod = mod;
|
||||
} else {
|
||||
if (!plugin_core_init(srv)) {
|
||||
_server_module_release(sm);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!plugins_activate_module(srv, sm)) {
|
||||
_server_module_release(sm);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
plugin *angel_plugin_register(server *srv, module *mod, const gchar *name, PluginInit init) {
|
||||
Plugins *ps = &srv->plugins;
|
||||
server_module *sm;
|
||||
plugin *p;
|
||||
const gchar* modname = mod ? mod->name->str : "core";
|
||||
|
||||
sm = g_hash_table_lookup(ps->load_module_refs, modname);
|
||||
if (!sm) {
|
||||
ERROR(srv, "Module '%s' not loaded; cannot load plugin '%s'", mod->name->str, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = plugin_new(name);
|
||||
if (!init(srv, p)) {
|
||||
plugin_free(srv, p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_ptr_array_add(sm->plugins, p);
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
#include <lighttpd/angel_plugin_core.h>
|
||||
|
||||
gboolean plugin_core_init(server *srv) {
|
||||
/* load core plugins */
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
#include <lighttpd/angel_base.h>
|
||||
|
||||
server* server_new(const gchar *module_dir) {
|
||||
server *srv = g_slice_new0(server);
|
||||
|
||||
/* TODO: handle sinals */
|
||||
|
||||
srv->loop = ev_default_loop(0);
|
||||
log_init(srv);
|
||||
plugins_init(srv, module_dir);
|
||||
return srv;
|
||||
}
|
||||
|
||||
void server_free(server* srv) {
|
||||
plugins_clear(srv);
|
||||
|
||||
log_clean(srv);
|
||||
g_slice_free(server, srv);
|
||||
}
|
|
@ -11,8 +11,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* from server.h */
|
||||
|
||||
#if REMOVE_PATH_FROM_FILE
|
||||
const char *remove_path(const char *path) {
|
||||
char *p = strrchr(path, DIR_SEPERATOR);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
#include <lighttpd/module.h>
|
||||
|
||||
modules *modules_init(gpointer main, const gchar *module_dir) {
|
||||
modules *modules_new(gpointer main, const gchar *module_dir) {
|
||||
modules *m = g_slice_new(modules);
|
||||
|
||||
m->version = MODULE_VERSION;
|
||||
|
@ -26,7 +26,7 @@ module *module_lookup(modules *mods, const gchar *name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void modules_cleanup(modules* mods) {
|
||||
void modules_free(modules* mods) {
|
||||
/* unload all modules */
|
||||
GArray *a = mods->mods;
|
||||
module *mod;
|
||||
|
|
|
@ -91,7 +91,7 @@ server* server_new(const gchar *module_dir) {
|
|||
|
||||
srv->sockets = g_ptr_array_new();
|
||||
|
||||
srv->modules = modules_init(srv, module_dir);
|
||||
srv->modules = modules_new(srv, module_dir);
|
||||
|
||||
srv->plugins = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
srv->options = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, server_value_free);
|
||||
|
@ -166,7 +166,7 @@ void server_free(server* srv) {
|
|||
}
|
||||
|
||||
/* release modules */
|
||||
modules_cleanup(srv->modules);
|
||||
modules_free(srv->modules);
|
||||
|
||||
plugin_free(srv, srv->core_plugin);
|
||||
|
||||
|
|
Loading…
Reference in New Issue