Browse Source

implement loading of modules

personal/stbuehler/wip
Thomas Porzelt 14 years ago
parent
commit
59fdb03ee0
  1. 5
      src/lighttpd.c
  2. 153
      src/module.c
  3. 20
      src/module.h
  4. 23
      src/plugin.c
  5. 5
      src/plugin.h
  6. 53
      src/plugin_core.c
  7. 17
      src/server.c
  8. 4
      src/server.h
  9. 5
      src/wscript
  10. 6
      wscript

5
src/lighttpd.c

@ -17,6 +17,7 @@ int main(int argc, char *argv[]) {
gboolean free_config_path = TRUE;
gchar *config_path = NULL;
gchar *module_dir = NULL;
gboolean luaconfig = FALSE;
gboolean test_config = FALSE;
gboolean show_version = FALSE;
@ -27,6 +28,7 @@ int main(int argc, char *argv[]) {
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &config_path, "filename/path of the config", "PATH" },
{ "lua", 'l', 0, G_OPTION_ARG_NONE, &luaconfig, "use the lua config frontend", NULL },
{ "test", 't', 0, G_OPTION_ARG_NONE, &test_config, "test config and exit", NULL },
{ "module-dir", 'm', 0, G_OPTION_ARG_STRING, &module_dir, "module directory", NULL },
{ "version", 'v', 0, G_OPTION_ARG_NONE, &show_version, "show version and exit", NULL },
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
@ -67,7 +69,8 @@ int main(int argc, char *argv[]) {
srv = server_new();
plugin_register(srv, "core", plugin_core_init);
srv->module_dir = module_dir;
srv->core_plugin = plugin_register(srv, "core", plugin_core_init);
/* if no path is specified for the config, read lighttpd.conf from current directory */
if (config_path == NULL) {

153
src/module.c

@ -0,0 +1,153 @@
#include "base.h"
#include "module.h"
modules *modules_init(gpointer main) {
modules *m = g_slice_new(modules);
m->version = MODULE_VERSION;
m->main = main;
m->mods = g_array_new(FALSE, TRUE, sizeof(module*));
return m;
}
/* for internal use only */
static module *module_lookup(modules *mods, const gchar *name) {
module *mod;
GArray *a = mods->mods;
for (guint i = 0; i < a->len; i++) {
mod = g_array_index(a, module*, i);
if (mod != NULL && g_str_equal(mod->name->str, name))
return mod;
}
return NULL;
}
void modules_cleanup(server *srv) {
/* unload all modules */
GArray *a = srv->modules->mods;
module *mod;
for (guint i = 0; i < a->len; i++) {
mod = g_array_index(a, module*, i);
if (!mod)
continue;
module_release(srv->modules, mod);
}
g_array_free(srv->modules->mods, TRUE);
g_slice_free(modules, srv->modules);
if (srv->module_dir)
g_free(srv->module_dir);
}
module* module_load(modules *mods, const gchar* name) {
module *mod;
ModuleInit m_init;
GString *m_init_str, *m_free_str;
guint i;
mod = module_lookup(mods, name);
if (mod) {
/* module already loaded, increment refcount and return */
mod->refcount++;
return mod;
}
mod = g_slice_new0(module);
mod->name = g_string_new(name);
mod->refcount = 1;
mod->path = g_module_build_path(((server *)mods->main)->module_dir, name);
TRACE(mods->main, "loading module '%s' from path: %s", name, mod->path);
mod->module = g_module_open(mod->path, G_MODULE_BIND_LAZY);
if (!mod->module) {
g_string_free(mod->name, TRUE);
g_free(mod->path);
g_slice_free(module, mod);
return NULL;
}
/* temporary strings for mod_xyz_init and mod_xyz_free */
m_init_str = g_string_new(name);
g_string_append_len(m_init_str, CONST_STR_LEN("_init"));
m_free_str = g_string_new(name);
g_string_append_len(m_free_str, CONST_STR_LEN("_free"));
if (!g_module_symbol(mod->module, m_init_str->str, (gpointer *)&m_init)
|| !g_module_symbol(mod->module, m_free_str->str, (gpointer *)&mod->free)
|| m_init == NULL || mod->free == NULL) {
/* mod_init or mod_free couldn't be located, something went wrong */
g_string_free(m_init_str, TRUE);
g_string_free(m_free_str, TRUE);
g_free(mod->path);
g_string_free(mod->name, TRUE);
g_slice_free(module, mod);
return NULL;
}
/* call mod_xyz_init */
if (!m_init(mods, mod)) {
g_string_free(m_init_str, TRUE);
g_string_free(m_free_str, TRUE);
g_free(mod->path);
g_string_free(mod->name, TRUE);
g_slice_free(module, mod);
return NULL;
}
/* insert into free slot */
for (i = 0; i < mods->mods->len; i++) {
if (!g_array_index(mods->mods, module*, i))
{
g_array_index(mods->mods, module*, i) = mod;
break;
}
}
/* if no free slot was found, append */
if (i == mods->mods->len)
g_array_append_val(mods->mods, mod);
/* free temp strings */
g_string_free(m_free_str, TRUE);
g_string_free(m_init_str, TRUE);
return mod;
}
void module_release(modules *mods, module *mod) {
guint i;
if (--mod->refcount > 0)
return;
for (i = 0; i < mods->mods->len; i++) {
if (g_array_index(mods->mods, module*, i) == mod)
{
g_array_index(mods->mods, module*, i) = NULL;
break;
}
}
mod->free(mods, mod);
g_module_close(mod->module);
g_free(mod->path);
g_string_free(mod->name, TRUE);
g_slice_free(module, mod);
}
void module_release_name(modules *mods, const gchar* name) {
module *mod = module_lookup(mods, name);
if (mod)
module_release(mods, mod);
}

20
src/module.h

@ -6,14 +6,14 @@
#define MODULE_VERSION ((guint) 0x00000001)
#define MODULE_VERSION_CHECK(mods) do { \
if (mods->version != MODULE_VERSION) { \
ERROR("Version mismatch for modules system: is %u, expected %u", mods->version, MODULE_VERSION); \
ERROR(mods->main, "Version mismatch for modules system: is %u, expected %u", mods->version, MODULE_VERSION); \
return FALSE; \
} } while(0)
/** see module_load */
#define MODULE_DEPENDS(mods, name) do { \
if (!modules_load(mods, name)) { \
ERROR("Couldn't load dependency '%s'", name); \
if (!module_load(mods, name)) { \
ERROR(mods->main, "Couldn't load dependency '%s'", name); \
return FALSE; \
} } while(0)
@ -29,21 +29,23 @@ typedef gboolean (*ModuleFree)(modules *mods, module *mod);
struct module {
gint refcount; /**< count how often module is used. module gets unloaded if refcount reaches zero. */
gchar *name; /**< name of module, can be set my plugin_init */
GString *name; /**< name of module, can be set my plugin_init */
GModule *module; /**< glib handle */
gchar *path; /**< path to the module file */
gpointer config; /**< private module data */
ModuleFree free; /**< if set by plugin_init it gets called before module is unloaded */
};
struct modules {
guint version; /**< api version */
GHashTable *mods; /**< hash table of modules */
GArray *mods; /**< array of (module*) */
gpointer main; /**< pointer to a application specific main structure, e.g. server */
};
LI_API modules* modules_init(gpointer main);
LI_API void modules_cleanup(server *srv);
/** 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.
@ -52,7 +54,7 @@ LI_API modules* modules_init(gpointer main);
LI_API module* module_load(modules *mods, const gchar* name);
LI_API void module_acquire(module *mod);
LI_API void module_release(modules *mods, module *module);
LI_API void module_release_name(modules *mods, const char* name);
LI_API void module_release(modules *mods, module *mod);
LI_API void module_release_name(modules *mods, const gchar* name);
#endif

23
src/plugin.c

@ -3,6 +3,7 @@
#include "log.h"
static gboolean plugin_load_default_option(server *srv, server_option *sopt);
static void plugin_free_default_options(server *srv, plugin *p);
static plugin* plugin_new(const gchar *name) {
plugin *p = g_slice_new0(plugin);
@ -58,6 +59,7 @@ void plugin_free(server *srv, plugin *p) {
}
g_hash_table_remove(srv->plugins, p->name);
plugin_free_default_options(srv, p);
plugin_free_options(srv, p);
plugin_free_actions(srv, p);
plugin_free_setups(srv, p);
@ -89,22 +91,22 @@ void server_plugins_free(server *srv) {
g_hash_table_destroy(srv->setups);
}
gboolean plugin_register(server *srv, const gchar *name, PluginInit init) {
plugin *plugin_register(server *srv, const gchar *name, PluginInit init) {
plugin *p;
if (!init) {
ERROR(srv, "Module '%s' needs an init function", name);
return FALSE;
return NULL;
}
if (g_atomic_int_get(&srv->state) != SERVER_STARTING) {
ERROR(srv, "Cannot register plugin '%s' after server was started", name);
return FALSE;
return NULL;
}
if (g_hash_table_lookup(srv->plugins, name)) {
ERROR(srv, "Module '%s' already registered", name);
return FALSE;
return NULL;
}
p = plugin_new(name);
@ -125,7 +127,7 @@ gboolean plugin_register(server *srv, const gchar *name, PluginInit init) {
so->p ? so->p->name : "<none>",
p->name);
plugin_free(srv, p);
return FALSE;
return NULL;
}
so = g_slice_new0(server_option);
so->type = po->type;
@ -152,7 +154,7 @@ gboolean plugin_register(server *srv, const gchar *name, PluginInit init) {
sa->p ? sa->p->name : "<none>",
p->name);
plugin_free(srv, p);
return FALSE;
return NULL;
}
sa = g_slice_new0(server_action);
sa->create_action = pa->create_action;
@ -173,7 +175,7 @@ gboolean plugin_register(server *srv, const gchar *name, PluginInit init) {
ss->p ? ss->p->name : "<none>",
p->name);
plugin_free(srv, p);
return FALSE;
return NULL;
}
ss = g_slice_new0(server_setup);
ss->setup = ps->setup;
@ -182,7 +184,7 @@ gboolean plugin_register(server *srv, const gchar *name, PluginInit init) {
}
}
return TRUE;
return p;
}
@ -396,7 +398,7 @@ static gboolean plugin_load_default_option(server *srv, server_option *sopt) {
return TRUE;
}
void plugins_free_default_options(server *srv) {
static void plugin_free_default_options(server *srv, plugin *p) {
static const option_value oempty = {0};
GHashTableIter iter;
gpointer k, v;
@ -408,6 +410,9 @@ void plugins_free_default_options(server *srv) {
mark.sopt = sopt;
mark.ndx = sopt->index;
if (sopt->p != p)
continue;
mark.value = g_array_index(srv->option_def_values, option_value, sopt->index);
release_option(srv, &mark);

5
src/plugin.h

@ -133,7 +133,7 @@ struct server_setup {
};
/* Needed by modules to register their plugin(s) */
LI_API gboolean plugin_register(server *srv, const gchar *name, PluginInit init);
LI_API plugin *plugin_register(server *srv, const gchar *name, PluginInit init);
/* Internal needed functions */
LI_API void plugin_free(server *srv, plugin *p);
@ -156,9 +156,6 @@ LI_API action* create_action(server *srv, const gchar *name, value *value);
/** For setup function, e.g. 'listen "127.0.0.1:8080"'; free value after call */
LI_API gboolean call_setup(server *srv, const char *name, value *val);
LI_API void plugins_free_default_options(server *srv);
/** free val after call */
LI_API gboolean plugin_set_default_option(server *srv, const gchar* name, value *val);

53
src/plugin_core.c

@ -150,6 +150,7 @@ static action_result core_handle_static(connection *con, gpointer param) {
} else {
struct stat st;
fstat(fd, &st);
#ifdef FD_CLOEXEC
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
@ -450,6 +451,57 @@ static gboolean core_workers(server *srv, plugin* p, value *val) {
return TRUE;
}
static gboolean core_module_load(server *srv, plugin* p, value *val) {
value *mods = value_new_list();
UNUSED(p);
if (!g_module_supported()) {
ERROR(srv, "%s", "module loading not supported on this platform");
value_free(mods);
return FALSE;
}
if (val->type == VALUE_STRING) {
/* load only one module */
value *name = value_new_string(value_extract(val).string);
g_array_append_val(mods->data.list, name);
} else if (val->type == VALUE_LIST) {
/* load a list of modules */
for (guint i = 0; i < val->data.list->len; i++) {
value *v = g_array_index(val->data.list, value*, i);
if (v->type != VALUE_STRING) {
ERROR(srv, "module_load takes either a string or a list of strings as parameter, list with %s entry given", value_type_string(v->type));
value_free(mods);
return FALSE;
}
}
mods->data.list = value_extract(val).list;
} else {
ERROR(srv, "module_load takes either a string or a list of strings as parameter, %s given", value_type_string(val->type));
return FALSE;
}
/* parameter types ok, load modules */
for (guint i = 0; i < mods->data.list->len; i++) {
GString *name = g_array_index(mods->data.list, value*, i)->data.string;
if (!module_load(srv->modules, name->str)) {
ERROR(srv, "could not load module '%s': %s", name->str, g_module_error());
value_free(mods);
return FALSE;
}
TRACE(srv, "loaded module '%s'", name->str);
}
value_free(mods);
return TRUE;
}
/*
* OPTIONS
*/
static gboolean core_option_log_parse(server *srv, plugin *p, size_t ndx, value *val, option_value *oval) {
GHashTableIter iter;
gpointer k, v;
@ -741,6 +793,7 @@ static const plugin_setup setups[] = {
{ "listen", core_listen },
{ "event_handler", core_event_handler },
{ "workers", core_workers },
{ "module_load", core_module_load },
{ NULL, NULL }
};

17
src/server.c

@ -60,6 +60,8 @@ server* server_new() {
srv->sockets = g_array_new(FALSE, TRUE, sizeof(server_socket*));
srv->modules = modules_init(srv);
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);
srv->actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, server_action_free);
@ -94,6 +96,14 @@ void server_free(server* srv) {
}
}
action_release(srv, srv->mainaction);
/* release modules */
modules_cleanup(srv);
plugin_free(srv, srv->core_plugin);
g_array_free(srv->option_def_values, TRUE);
/* free all workers */
{
guint i;
@ -121,13 +131,6 @@ void server_free(server* srv) {
g_array_free(srv->sockets, TRUE);
}
action_release(srv, srv->mainaction);
if (srv->option_def_values->len) {
plugins_free_default_options(srv);
}
g_array_free(srv->option_def_values, TRUE);
log_cleanup(srv);
server_plugins_free(srv);

4
src/server.h

@ -41,7 +41,11 @@ struct server {
GArray *sockets; /** array of (server_socket*) */
gchar *module_dir;
struct modules *modules;
GHashTable *plugins; /**< const gchar* => (plugin*) */
struct plugin *core_plugin;
/* registered by plugins */
GHashTable *options; /**< const gchar* => (server_option*) */

5
src/wscript

@ -4,7 +4,7 @@
#import Object, Params, os, sys
import Options
common_uselib = 'glib gthread'
common_uselib = 'glib gthread gmodule'
common_source='''
actions.c
@ -20,6 +20,7 @@ common_source='''
http_headers.c
http_request_parser.rl
log.c
module.c
network.c
network_write.c network_writev.c
network_linux_sendfile.c
@ -74,7 +75,7 @@ main_source = '''
def lighty_mod(bld, target, src, uselib = '', option = ''):
if option and not getattr(Options.options, option): return
mod = bld.new_task_gen('cc', 'plugin')
mod = bld.new_task_gen('cc', 'shlib')
mod.target = target
mod.source = src
mod.uselib += 'lightymod ' + common_uselib + uselib

6
wscript

@ -36,7 +36,7 @@ def set_options(opt):
opt.add_option('--build-static', action='store_true', help='build a static lighttpd with all modules added', dest = 'buildstatic', default = False)
opt.add_option('--append', action='store', help='Append string to binary names / library dir', dest = 'append', default = '')
opt.add_option('--lib-dir', action='store', help='Module directory [default: prefix + /lib/lighttpd + append]', dest = 'libdir', default = '')
opt.add_option('--debug', action='store_true', help='Do not compile with -O2', dest = 'debug', default = False)
from Tools.config_c import enumerator_base, check_data
@ -396,6 +396,10 @@ def configure(conf):
incdir = conf.env['CPPPATH_gthread'][0]
conf.env['CPPPATH_gthread'] += [ incdir+'/glib-2.0/', incdir + '/glib-2.0/include/' ]
PKGCONFIG(conf, "gmodule-2.0", uselib = 'gmodule', mandatory = 1)
incdir = conf.env['CPPPATH_gmodule'][0]
conf.env['CPPPATH_gmodule'] += [ incdir+'/glib-2.0/', incdir + '/glib-2.0/include/' ]
#if opts.libfcgi:
#CHECK_INCLUDE_FILES(conf, "fastcgi.h", "HAVE_FASTCGI_H", uselib = 'libfcgi')
#if not conf.is_defined("HAVE_FASTCGI_H"):

Loading…
Cancel
Save