feat: rework on plugin support
gitea-sync/ant-http/pipeline/head This commit looks good Details

- New plugin interface that supports multiple instances
- Fix and improve memory bugs
- Refactory and cleanup lib
- Improve scheduler
This commit is contained in:
DanyLE 2024-03-13 18:07:07 +01:00
parent 3bedc3ffb5
commit 58a7738afe
19 changed files with 389 additions and 315 deletions

View File

@ -22,7 +22,8 @@ libantd_la_SOURCES = lib/ini.c \
lib/sha1.c \
lib/list.c \
lib/bst.c \
lib/scheduler.c
lib/scheduler.c \
lib/plugin.c
pkginclude_HEADERS = lib/ini.h \
lib/handle.h \

View File

@ -3,8 +3,6 @@
plugins=/opt/www/lib/
; plugin extension
plugins_ext=.so
; SQLITE database path
database=/opt/www/database/
; tmp dir
tmpdir=/opt/www/tmp/
; max concurent connection

View File

@ -63,8 +63,8 @@ static void init_plugins()
if (value && (strncmp(value, "1", 1) == 0 || strncmp(value, "true", 3) == 0))
{
// load the plugin
LOG("Plugin %s: autoloading...", it->key);
plugin_load(it->key, config);
LOG("Plugin %s: auto loading...", it->key);
UNUSED(antd_plugin_load(it->key));
}
}
}
@ -105,23 +105,6 @@ static int config_handler(void *conf, const char *section, const char *name,
free(pconfig->plugins_ext);
pconfig->plugins_ext = strdup(value);
}
else if (MATCH("SERVER", "database"))
{
if (stat(value, &st) == -1)
mkdirp(value, 0700);
tmp = realpath(value, NULL);
if (!tmp)
{
ERROR("Unable to query real path for %s: %s", value, strerror(errno));
}
else
{
if (pconfig->db_path)
free(pconfig->db_path);
pconfig->db_path = tmp;
LOG("Database root is %s", pconfig->db_path);
}
}
else if (MATCH("SERVER", "tmpdir"))
{
if (stat(value, &st) == -1)
@ -341,6 +324,13 @@ void load_config(const char *file)
LOG("SSL Cipher suite: %s", g_server_config.ssl_cipher);*/
#endif
}
set_mimes_list(g_server_config.mimes);
#ifdef USE_ZLIB
if(g_server_config.gzip_enable && g_server_config.gzip_types != NULL)
{
set_gzip_types(g_server_config.gzip_types);
}
#endif
LOG("%d mimes entries found", g_server_config.mimes->size);
// Init plugins if necessary
init_plugins();
@ -361,9 +351,17 @@ void destroy_config()
if (g_server_config.ssl_cipher)
free(g_server_config.ssl_cipher);
if (g_server_config.gzip_types)
{
list_free(&g_server_config.gzip_types);
#ifdef USE_ZLIB
set_gzip_types(g_server_config.gzip_types);
#endif
}
if (g_server_config.mimes)
{
freedict(g_server_config.mimes);
set_mimes_list(NULL);
}
if (g_server_config.stat_fifo_path)
free(g_server_config.stat_fifo_path);
if (g_server_config.plugins)
@ -371,9 +369,18 @@ void destroy_config()
for_each_assoc(it, g_server_config.plugins)
{
freedict((dictionary_t)it->value);
it->value = NULL;
}
freedict(g_server_config.plugins);
}
if(g_server_config.sslcert)
{
free(g_server_config.sslcert);
}
if(g_server_config.sslkey)
{
free(g_server_config.sslkey);
}
if (g_server_config.ports)
{
port_config_t *cnf;
@ -396,4 +403,5 @@ void destroy_config()
freedict(g_server_config.ports);
}
LOG("Unclosed connection: %d", g_server_config.connection);
LOG("Config destroyed");
}

View File

@ -254,6 +254,7 @@ static void *check_proxy(antd_request_t *rq, const char *path, const char *query
if (!ret)
{
free(task);
return NULL;
}
@ -367,7 +368,7 @@ void *decode_request_header(void *data)
dictionary_t request = dvalue(rq->request, "REQUEST_DATA");
char *port_s = (char *)dvalue(rq->request, "SERVER_PORT");
port_config_t *pcnf = (port_config_t *)dvalue(g_server_config.ports, port_s);
antd_task_t *task;
antd_task_t *task = NULL;
// first real all header
// this for check if web socket is enabled
@ -757,7 +758,6 @@ void *decode_post_request(void *data)
{
// WARN: this may not work on ssl socket
// antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_READABLE | TASK_EVT_ON_WRITABLE);
// task->handle = decode_post_request;
antd_error(rq->client, 400, "Bad Request, missing content data");
return task;
}

16
httpd.c
View File

@ -140,7 +140,6 @@ static void configure_context(SSL_CTX *ctx)
static void stop_serve(int dummy)
{
UNUSED(dummy);
// close log server
closelog();
sigset_t mask;
@ -151,7 +150,7 @@ static void stop_serve(int dummy)
sigaddset(&mask, SIGABRT);
sigprocmask(SIG_BLOCK, &mask, NULL);
antd_scheduler_destroy(scheduler);
unload_all_plugin();
antd_unload_all_plugin();
#ifdef USE_OPENSSL
// DEPRECATED FIPS_mode_set(0);
SSL_CTX_free(ctx);
@ -165,6 +164,7 @@ static void stop_serve(int dummy)
#endif
destroy_config();
sigprocmask(SIG_UNBLOCK, &mask, NULL);
exit(dummy);
}
static void antd_monitor(port_config_t *pcnf, int sock)
@ -182,6 +182,7 @@ static void antd_monitor(port_config_t *pcnf, int sock)
// just dump the scheduler when we have a connection
antd_client_t *client = (antd_client_t *)malloc(sizeof(antd_client_t));
antd_request_t *request = (antd_request_t *)malloc(sizeof(*request));
request->context = NULL;
request->client = client;
request->request = dict();
client->zstream = NULL;
@ -378,8 +379,7 @@ int main(int argc, char *argv[])
if (scheduler == NULL)
{
ERROR("Unable to initialise scheduler. Exit");
stop_serve(0);
exit(1);
stop_serve(1);
}
FD_ZERO(&master_set);
for_each_assoc(it, g_server_config.ports)
@ -411,15 +411,13 @@ int main(int argc, char *argv[])
if (nlisten == 0)
{
ERROR("No port is listened, quit!!");
stop_serve(0);
exit(1);
stop_serve(1);
}
// Start scheduler
if (pthread_create(&sched_th, NULL, (void *(*)(void *))antd_scheduler_wait, (void *)scheduler) != 0)
{
ERROR("pthread_create: cannot start scheduler thread");
stop_serve(0);
exit(1);
stop_serve(1);
}
else
{
@ -460,5 +458,5 @@ int main(int argc, char *argv[])
}
}
stop_serve(0);
return (0);
return 0;
}

View File

@ -152,6 +152,7 @@ void free_association(chain_t *asoc)
if (a->key)
{
//printf("Free key %s\n", a->key);
free(a->key);
if (a->value)
free(a->value);

View File

@ -100,11 +100,31 @@ int require_plugin(const char *name)
return 0;
}
#ifdef USE_ZLIB
static list_t g_gzip_types = NULL;
void set_gzip_types(list_t list)
{
g_gzip_types = list;
}
int compressable(char *ctype)
{
UNUSED(ctype);
if (g_gzip_types == NULL)
return 0;
item_t it;
list_for_each(it, g_gzip_types)
{
if(it->type == LIST_TYPE_POINTER && it->value.ptr)
{
//LOG("Checking content type %s against GZIP support %s", ctype,(const char *)it->value.ptr);
if (regex_match((const char *)it->value.ptr, ctype, 0, NULL))
{
return 1;
}
}
}
return 0;
}
#endif
const char *get_status_str(int stat)
{

View File

@ -5,6 +5,7 @@
#include "list.h"
#include "dictionary.h"
#include "plugin.h"
#define SERVER_NAME "Antd"
#define IS_POST(method) (strcmp(method, "POST") == 0)
@ -28,9 +29,6 @@
#define ANTD_CLIENT_RQ_DATA_DECODE 0x7
#define ANTD_CLIENT_PROXY_MONITOR 0x8
#define ANTD_PLUGIN_READY 0x0
#define ANTD_PLUGIN_PANNIC 0x1
#define ANTD_PLUGIN_INIT 0x2
#define MAX_PATH_LEN 256
typedef enum
@ -63,6 +61,7 @@ typedef struct
{
antd_client_t *client;
dictionary_t request;
antd_plugin_ctx_t * context;
} antd_request_t;
typedef struct
@ -73,23 +72,12 @@ typedef struct
} antd_response_header_t;
typedef struct
{
char name[MAX_PATH_LEN];
char dbpath[MAX_PATH_LEN];
char tmpdir[MAX_PATH_LEN];
char pdir[MAX_PATH_LEN];
dictionary_t config;
int raw_body;
int status;
void *instance_data;
} plugin_header_t;
void set_nonblock(int socket);
//void set_block(int socket);
int __attribute__((weak)) compressable(char *ctype);
#ifdef USE_ZLIB
int compressable(char *ctype);
void set_gzip_types(list_t list);
#endif
void antd_send_header(void *, antd_response_header_t *);
const char *get_status_str(int stat);
int __t(void *, const char *, ...);

51
lib/plugin.c Normal file
View File

@ -0,0 +1,51 @@
#include "plugin_ctx.h"
#include "plugin.h"
const char * antd_plugin_basedir(antd_plugin_ctx_t * ctx)
{
return ctx->basedir;
}
const char * antd_plugin_tmpdir(antd_plugin_ctx_t * ctx)
{
return ctx->tmpdir;
}
const char * antd_plugin_confdir(antd_plugin_ctx_t *ctx)
{
if(ctx->confdir == NULL)
{
struct stat st;
ctx->confdir = __s("%s%s%s", ctx->basedir,DIR_SEP, ctx->name);
if (stat(ctx->confdir, &st) == -1)
mkdir(ctx->confdir, 0755);
}
return ctx->confdir;
}
const char * antd_plugin_name(antd_plugin_ctx_t *ctx)
{
return ctx->name;
}
void antd_plugin_set_status(antd_plugin_ctx_t * ctx, int stat)
{
ctx->status = stat;
}
int antd_plugin_status(antd_plugin_ctx_t * ctx)
{
return ctx->status;
}
void antd_plugin_use_raw_body(antd_plugin_ctx_t * ctx)
{
ctx->raw_body = 1;
}
int antd_plugin_is_raw_body(antd_plugin_ctx_t *ctx)
{
return ctx->raw_body == 1;
}
void* antd_plugin_data(antd_plugin_ctx_t* ctx)
{
return ctx->data;
}
dictionary_t antd_plugin_config(antd_plugin_ctx_t* ctx)
{
return ctx->config;
}

View File

@ -1,61 +1,41 @@
#ifndef PLUGIN_H
#define PLUGIN_H
#include <sys/stat.h>
#define ANTD_PLUGIN_READY 0x0
#define ANTD_PLUGIN_PANNIC 0x1
#define ANTD_PLUGIN_INIT 0x2
#define PLUGIN_INIT "create"
#define PLUGIN_HANDLE "handle"
#define PLUGIN_DROP "drop"
#define DEF_PLUGIN_INTERFACE(name, param, ret) ret##name(param)
#include "utils.h"
#include "handle.h"
#include "dictionary.h"
#define PLUGIN_PANIC(ctx, a, ...) \
ERROR("%s: " a, antd_plugin_name(ctx), ##__VA_ARGS__); \
antd_plugin_set_status(ctx, ANTD_PLUGIN_PANNIC);
char* config_dir();
/*Default function for plugin*/
// init the plugin
void init();
void destroy();
void* handle(void*);
plugin_header_t* meta();
void use_raw_body();
typedef struct _plugin_ctx_t antd_plugin_ctx_t;
/*
STATIC PART, should be included in any plugin
*/
#ifdef PLUGIN_IMPLEMENT
const char *antd_plugin_basedir(antd_plugin_ctx_t *);
const char *antd_plugin_tmpdir(antd_plugin_ctx_t *);
const char *antd_plugin_confdir(antd_plugin_ctx_t *);
const char *antd_plugin_name(antd_plugin_ctx_t *);
void antd_plugin_set_status(antd_plugin_ctx_t *, int);
int antd_plugin_status(antd_plugin_ctx_t *);
void antd_plugin_use_raw_body(antd_plugin_ctx_t *);
int antd_plugin_is_raw_body(antd_plugin_ctx_t *);
void *antd_plugin_data(antd_plugin_ctx_t *);
dictionary_t antd_plugin_config(antd_plugin_ctx_t*);
#define PLUGIN_PANIC(a,...) \
ERROR("%s: "a,__plugin__.name, ##__VA_ARGS__); \
__plugin__.status = ANTD_PLUGIN_PANNIC;
/*Default interfaces shall be implemented by plugin*/
void *create(antd_plugin_ctx_t *);
void drop(antd_plugin_ctx_t *);
void *handle(void *);
static plugin_header_t __plugin__;
// private function
void __init_plugin__(plugin_header_t* pl, dictionary_t* conf){
(void) memcpy(&__plugin__, pl, sizeof(plugin_header_t));
__plugin__.status = ANTD_PLUGIN_READY;
init();
};
void use_raw_body()
{
__plugin__.raw_body = 1;
}
plugin_header_t* meta()
{
return &__plugin__;
}
char* config_dir()
{
struct stat st;
char* path = __s("%s%s%s", __plugin__.pdir,DIR_SEP, __plugin__.name);
if (stat(path, &st) == -1)
mkdir(path, 0755);
return path;
}
void __release__()
{
destroy();
}
#endif
#endif

18
lib/plugin_ctx.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef PLUGIN_CTX_H
#define PLUGIN_CTX_H
#include "handle.h"
struct _plugin_ctx_t
{
char * name;
const char * tmpdir;
const char * basedir;
char * confdir;
int raw_body;
int status;
dictionary_t config;
void * data;
void *(*handle)(void *);
void *(*create)(struct _plugin_ctx_t *);
void (*drop)(struct _plugin_ctx_t *);
} ;
#endif

View File

@ -533,7 +533,7 @@ void antd_scheduler_destroy(antd_scheduler_t *scheduler)
*/
antd_task_t *antd_create_task(void *(*handle)(void *), void *data, void *(*callback)(void *), time_t atime)
{
antd_task_t *task = (antd_task_t *)malloc(sizeof *task);
antd_task_t *task = (antd_task_t *)malloc(sizeof(antd_task_t));
task->stamp = (unsigned long)time(NULL);
task->data = data;
task->handle = handle;

View File

@ -1,8 +1,6 @@
#ifndef ANT_SCHEDULER
#define ANT_SCHEDULER
#include <pthread.h>
#include <semaphore.h>
#include <stdint.h>

View File

@ -46,6 +46,8 @@ THE SOFTWARE.
#include "dictionary.h"
// #include <time.h>
static dictionary_t g_mime_list = NULL;
/**
* Trim a string by a character on both ends
* @param str The target string
@ -184,8 +186,14 @@ void verify_header(char *k)
dictionary_t mimes_list()
{
return NULL;
return g_mime_list;
}
void set_mimes_list(dictionary_t dict)
{
g_mime_list = dict;
}
/*get mime file info from type*/
mime_t mime_from_type(const char *type)
{

View File

@ -34,6 +34,7 @@ THE SOFTWARE.
#include "dictionary.h"
#define STRINGIFY(x) #x
#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
#define EQU(a,b) (strcmp(a,b) == 0)
#define IEQU(a,b) (strcasecmp(a,b) == 0)
@ -44,9 +45,9 @@ THE SOFTWARE.
#define true 1
#define false 0
#define LOG(a,...) syslog (LOG_NOTICE,"ANTD_LOG@[%s: %d]: " a "\n", __FILE__, \
#define LOG(a,...) syslog (LOG_NOTICE,"ANTD_LOG@[%s:%d]: " a "\n", __FILE__, \
__LINE__, ##__VA_ARGS__)
#define ERROR(a,...) syslog (LOG_ERR, "ANTD_ERROR@[%s: %d]: " a "\n", __FILE__, \
#define ERROR(a,...) syslog (LOG_ERR, "ANTD_ERROR@[%s:%d]: " a "\n", __FILE__, \
__LINE__, ##__VA_ARGS__)
// add this to the utils
#define UNUSED(x) (void)(x)
@ -65,7 +66,8 @@ typedef union
struct sockaddr_in addr4;
} antd_sockaddr_t;
dictionary_t __attribute__((weak)) mimes_list();
dictionary_t mimes_list();
void set_mimes_list(dictionary_t);
char* __s(const char*,...);
void trim(char*,const char);
void removeAll(const char* path,int mode);

View File

@ -5,16 +5,21 @@
#include <sys/sendfile.h>
#include <unistd.h>
#include <stdio.h>
#include "plugin_manager.h"
#include "lib/utils.h"
#include "lib/handle.h"
#include "config.h"
#include "lib/plugin_ctx.h"
#include "plugin_manager.h"
struct plugin_entry {
struct plugin_entry *next;
char *name;
void *handle;
dictionary_t instances;
};
extern config_t g_server_config;
static void unload_plugin_by_name(const char *);
static void *plugin_from_file(char *name, char *path, dictionary_t conf);
/**
* Plugin table to store the loaded plugin
*/
@ -25,8 +30,12 @@ static struct plugin_entry *plugin_table[HASHSIZE];
* @param s plugin name
* @return a plugin entry in the plugin table
*/
struct plugin_entry *plugin_lookup(char *s)
static struct plugin_entry *plugin_lookup(const char *s)
{
if(!s)
{
return NULL;
}
struct plugin_entry *np;
for (np = plugin_table[hash(s, HASHSIZE)]; np != NULL; np = np->next)
if (strcmp(s, np->name) == 0)
@ -34,6 +43,136 @@ struct plugin_entry *plugin_lookup(char *s)
return NULL; /* not found */
}
static void antd_plugin_ctx_drop(struct plugin_entry* np, antd_plugin_ctx_t* ctx)
{
if(!ctx)
{
return;
}
if(ctx->drop)
{
if(ctx->name)
LOG("Release user resource for context: %s", ctx->name);
ctx->drop((void*)ctx);
}
if(ctx->name)
{
LOG("Dropping plugin context: %s", ctx->name);
if(np->instances)
{
dput(np->instances, ctx->name, NULL);
}
free(ctx->name);
}
if(ctx->confdir)
{
free(ctx->confdir);
}
free(ctx);
}
static antd_plugin_ctx_t* antd_plugin_ctx_lookup(struct plugin_entry* np, const char* name)
{
if(!np || !np->instances)
{
return NULL;
}
LOG("Looking for plugin context: %s", name);
antd_plugin_ctx_t* ctx = dvalue(np->instances, name);
if(ctx == NULL)
{
char *error;
LOG("Create new plugin context: %s", name);
ctx = (antd_plugin_ctx_t *)malloc(sizeof(antd_plugin_ctx_t));
if(!ctx)
{
ERROR("Unable to allocate memory for plugin context `%s`: %s", name, strerror(errno));
return NULL;
}
// init the context
ctx->basedir = g_server_config.plugins_dir;
ctx->tmpdir = g_server_config.tmpdir;
ctx->name = strdup(name);
ctx->confdir = NULL;
ctx->raw_body = 0;
ctx->status = ANTD_PLUGIN_INIT;
ctx->config=dvalue(g_server_config.plugins, name);
ctx->data = NULL;
ctx->handle = NULL;
ctx->create = NULL;
ctx->drop = NULL;
// look for handle function
ctx->handle = (void* (*)(void *))dlsym(np->handle, PLUGIN_HANDLE);
if ((error = dlerror()) != NULL)
{
ERROR("Problem when finding plugin handle function for %s : %s", name, error);
ctx->handle = NULL;
antd_plugin_ctx_drop(np, ctx);
return NULL;
}
// look for drop function
ctx->drop = (void (*)(antd_plugin_ctx_t *))dlsym(np->handle, PLUGIN_DROP);
if ((error = dlerror()) != NULL)
{
ERROR("Problem when finding plugin drop function for %s : %s", name, error);
ctx->drop = NULL;
antd_plugin_ctx_drop(np, ctx);
return NULL;
}
// look for init function
ctx->create = (void* (*)(antd_plugin_ctx_t *))dlsym(np->handle, PLUGIN_INIT);
if ((error = dlerror()) != NULL)
{
ERROR("Problem when finding plugin init function for %s : %s.", name, error);
ctx->create = NULL;
antd_plugin_ctx_drop(np, ctx);
return NULL;
}
else
{
// run the init function
ctx->data = ctx->create(ctx);
if(ctx->status == ANTD_PLUGIN_PANNIC)
{
ERROR("PANIC happens when init plugin context %s. drop it", name);
antd_plugin_ctx_drop(np, ctx);
return NULL;
}
ctx->status = ANTD_PLUGIN_READY;
}
dput(np->instances, name, (void*)ctx);
}
return ctx;
}
static void antd_plugin_entry_drop(struct plugin_entry* np)
{
if(!np)
{
return;
}
if(np->name)
{
LOG("Unloaded %s", np->name);
free(np->name);
}
if(np->instances)
{
chain_t it;
for_each_assoc(it, np->instances)
{
antd_plugin_ctx_drop(np,(antd_plugin_ctx_t*)it->value);
}
freedict(np->instances);
}
if(np->handle)
{
dlclose(np->handle);
}
free(np);
}
/**
* Load a plugin to the plugin table
* Only load when not available in the plugin table
@ -41,170 +180,76 @@ struct plugin_entry *plugin_lookup(char *s)
* @param config: plugin configuration
* @return pointer to the loaded plugin
*/
struct plugin_entry *plugin_load(char *name, dictionary_t pconf)
antd_plugin_ctx_t* antd_plugin_load(const char *name)
{
char *pname = NULL;
const char *plugin_file_name = NULL;
char path[BUFFLEN];
struct plugin_entry *np;
unsigned hashval;
plugin_header_t *(*metafn)();
plugin_header_t *meta = NULL;
int fromfd, tofd;
char *error;
struct stat st;
int is_tmp = 0;
antd_plugin_ctx_t *ctx;
dictionary_t pconf = dvalue(g_server_config.plugins, name);
if (pconf)
{
pname = dvalue(pconf, "name");
plugin_file_name = dvalue(pconf, "name");
}
if ((np = plugin_lookup(name)) == NULL)
if(plugin_file_name == NULL)
{
plugin_file_name = name;
}
if(plugin_file_name == NULL)
{
return NULL;
}
if ((np = plugin_lookup(plugin_file_name)) == NULL)
{ /* not found */
LOG("Loading plugin: %s...", name);
np = (struct plugin_entry *)malloc(sizeof(*np));
if (np == NULL || name == NULL)
LOG("Loading plugin: %s...", plugin_file_name);
np = (struct plugin_entry *)malloc(sizeof(struct plugin_entry));
np->instances = NULL;
if (np == NULL)
{
if (np)
free(np);
return NULL;
}
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, name, g_server_config.plugins_ext);
if (pname && strcmp(name, pname) != 0)
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, plugin_file_name, g_server_config.plugins_ext);
np->name = strdup(plugin_file_name);
// now load it from file
np->handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL /*| RTLD_NODELETE*/);
if (!np->handle)
{
// copy plugin file to tmpdir
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, pname, g_server_config.plugins_ext);
LOG("Original plugin file: %s", path);
if ((fromfd = open(path, O_RDONLY)) < 0)
{
ERROR("Unable to open file for reading %s: %s", path, strerror(errno));
return NULL;
}
if (stat(path, &st) != 0)
{
close(fromfd);
ERROR("Unable to get file stat %s: %s", path, strerror(errno));
return NULL;
}
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.tmpdir, name, g_server_config.plugins_ext);
LOG("TMP plugin file: %s", path);
if ((tofd = open(path, O_WRONLY | O_CREAT, 0600)) < 0)
{
close(fromfd);
ERROR("Unable open file for reading %s: %s", path, strerror(errno));
return NULL;
}
if (sendfile(tofd, fromfd, NULL, st.st_size) != st.st_size)
{
close(fromfd);
close(tofd);
ERROR("Unable to copy file: %s", strerror(errno));
return NULL;
}
is_tmp = 1;
}
np->name = strdup(name);
np->handle = plugin_from_file(name, path, pconf);
if (is_tmp)
{
//TODO change this
(void)remove(path);
}
if (np->handle == NULL)
{
if (np->name)
free(np->name);
if (np)
free(np);
ERROR("Cannot load plugin '%s' : '%s'", plugin_file_name, dlerror());
antd_plugin_entry_drop(np);
return NULL;
}
np->instances = dict();
hashval = hash(name, HASHSIZE);
np->next = plugin_table[hashval];
plugin_table[hashval] = np;
}
else /* already there */
{
LOG("The plugin %s id already loaded", name);
LOG("The plugin %s id already loaded", plugin_file_name);
}
// now look for the plugin context
ctx = antd_plugin_ctx_lookup(np, name);
// check if plugin is ready
metafn = (plugin_header_t * (*)()) dlsym(np->handle, "meta");
if ((error = dlerror()) != NULL)
if (ctx == NULL)
{
ERROR("Unable to fetch plugin meta-data: [%s] %s", name, error);
unload_plugin_by_name(name);
free(np);
ERROR("Unable to fetch plugin context for: [%s] %s", plugin_file_name, name);
return NULL;
}
meta = metafn();
LOG("PLugin status: [%s] %d", name, meta->status);
if (!meta || meta->status != ANTD_PLUGIN_READY)
LOG("PLugin instance status: [%s] %d", name, ctx->status);
if (ctx->status != ANTD_PLUGIN_READY)
{
ERROR("Plugin is not ready or error: [%s].", name);
unload_plugin_by_name(name);
free(np);
ERROR("Plugin instance is not ready or error: [%s].", name);
antd_plugin_ctx_drop(np, ctx);
return NULL;
}
return np;
}
/**
* Find a plugin in a file, and load it in to the plugin table
* @param name Name of the plugin
* @return
*/
static void *plugin_from_file(char *name, char *path, dictionary_t conf)
{
void *lib_handle;
char *error;
void (*fn)(plugin_header_t *, dictionary_t);
lib_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL /*| RTLD_NODELETE*/);
if (!lib_handle)
{
ERROR("Cannot load plugin '%s' : '%s'", name, dlerror());
return NULL;
}
fn = (void (*)(plugin_header_t *, dictionary_t))dlsym(lib_handle, "__init_plugin__");
if ((error = dlerror()) != NULL)
ERROR("Problem when finding plugin init function for %s : %s", name, error);
else
{
plugin_header_t header;
strncpy(header.name, name, MAX_PATH_LEN - 1);
strncpy(header.dbpath, g_server_config.db_path, MAX_PATH_LEN - 1);
strncpy(header.tmpdir, g_server_config.tmpdir, MAX_PATH_LEN - 1);
strncpy(header.pdir, g_server_config.plugins_dir, MAX_PATH_LEN - 1);
header.config = conf;
header.raw_body = 0;
header.status = ANTD_PLUGIN_INIT;
(*fn)(&header, conf);
}
// trick libc that we close this lib, but it is not realy deleted
return lib_handle;
return ctx;
}
void unload_plugin(struct plugin_entry *np)
{
char *error;
void (*fn)() = NULL;
// find and execute the exit function
fn = (void (*)())dlsym(np->handle, "__release__");
if ((error = dlerror()) != NULL)
{
ERROR("Cant not release plugin %s : %s", np->name, error);
}
if (fn)
{
(*fn)();
}
dlclose(np->handle);
LOG("Unloaded %s", np->name);
// free((void *) np->handle);
if (np->name)
free((void *)np->name);
}
/*
Unload a plugin by its name
*/
void unload_plugin_by_name(const char *name)
{
struct plugin_entry *np;
@ -212,7 +257,7 @@ void unload_plugin_by_name(const char *name)
np = plugin_table[hasval];
if (strcmp(np->name, name) == 0)
{
unload_plugin(np);
antd_plugin_entry_drop(np);
plugin_table[hasval] = np->next;
}
else
@ -226,14 +271,16 @@ void unload_plugin_by_name(const char *name)
}
if (np == NULL)
return; // the plugin is is not loaded
unload_plugin(np->next);
antd_plugin_entry_drop(np->next);
np->next = np->next->next;
}
}
*/
/**
* Unload all the plugin loaded on the plugin table
*/
void unload_all_plugin()
void antd_unload_all_plugin()
{
LOG("Unload all plugins");
for (int i = 0; i < HASHSIZE; i++)
@ -244,10 +291,14 @@ void unload_all_plugin()
while ((curr = *np) != NULL)
{
(*np) = (*np)->next;
unload_plugin(curr);
free(curr);
antd_plugin_entry_drop(curr);
//free(curr);
}
plugin_table[i] = NULL;
}
exit(0);
}
antd_plugin_handle_t antd_get_ctx_handle(antd_plugin_ctx_t *ctx)
{
return ctx->handle;
}

View File

@ -2,19 +2,12 @@
#define PLUGIN_MANAGER_H
#include "lib/dictionary.h"
#include "lib/plugin.h"
#include "lib/scheduler.h"
#define PLUGIN_HANDLER "handle"
typedef void*(*antd_plugin_handle_t)(void *);
struct plugin_entry {
struct plugin_entry *next;
char *name;
void *handle;
dictionary_t instances;
};
/* lookup: look for s in hashtable */
struct plugin_entry *plugin_lookup(char *s);
/* install: put (name, defn) in hashtable */
struct plugin_entry *plugin_load(char *name, dictionary_t config);
void unload_all_plugin();
void unload_plugin(struct plugin_entry*);
antd_plugin_ctx_t *antd_plugin_load(const char *name);
void antd_unload_all_plugin();
antd_plugin_handle_t antd_get_ctx_handle(antd_plugin_ctx_t *);
#endif

View File

@ -3,7 +3,6 @@
#endif
#include <sys/socket.h>
#include <poll.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
@ -534,13 +533,8 @@ void *proxify(void *data)
*/
void *execute_plugin(void *data, const char *pname)
{
void *(*fn)(void *);
plugin_header_t *(*metafn)();
plugin_header_t *meta = NULL;
struct plugin_entry *plugin;
char *error;
char pattern[256];
antd_plugin_ctx_t* ctx;
antd_request_t *rq = (antd_request_t *)data;
antd_task_t *task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE);
@ -561,58 +555,23 @@ void *execute_plugin(void *data, const char *pname)
rq->client->state = ANTD_CLIENT_PLUGIN_EXEC;
// load the plugin
pthread_mutex_lock(&server_mux);
plugin = plugin_load((char *)pname, dvalue(g_server_config.plugins, pname));
ctx = antd_plugin_load(pname);
pthread_mutex_unlock(&server_mux);
if (plugin == NULL)
if (ctx == NULL)
{
antd_error(rq->client, 503, "Requested service not found");
return task;
}
// check if the plugin want rawbody or decoded body
metafn = (plugin_header_t * (*)()) dlsym(plugin->handle, "meta");
if ((error = dlerror()) == NULL)
{
meta = metafn();
}
// load the function
fn = (void *(*)(void *))dlsym(plugin->handle, PLUGIN_HANDLER);
if ((error = dlerror()) != NULL)
{
ERROR("Problem when finding %s method from %s : %s", PLUGIN_HANDLER, pname, error);
antd_error(rq->client, 503, "Requested service not found");
return task;
}
rq->context = ctx;
// check if we need the raw data or not
if (meta && meta->raw_body == 1)
if (antd_plugin_is_raw_body(ctx) == 1)
{
task->handle = fn;
task->handle = antd_get_ctx_handle(ctx);
}
else
{
free(task);
task = antd_create_task(decode_post_request, (void *)rq, fn, rq->client->last_io);
task = antd_create_task(decode_post_request, (void *)rq, antd_get_ctx_handle(ctx), rq->client->last_io);
}
return task;
}
dictionary_t mimes_list()
{
return g_server_config.mimes;
}
#ifdef USE_ZLIB
int compressable(char *ctype)
{
if (!g_server_config.gzip_enable || g_server_config.gzip_types == NULL)
return 0;
item_t it;
list_for_each(it, g_server_config.gzip_types)
{
if (it->type == LIST_TYPE_POINTER && it->value.ptr && regex_match((const char *)it->value.ptr, ctype, 0, NULL))
{
return 1;
}
}
return 0;
}
#endif

View File

@ -1,8 +1,8 @@
#ifndef HTTP_SERVER
#define HTTP_SERVER
void *accept_request(void *);
void *proxify(void *data);
void *resolve_request(void *data);
void *finish_request(void *data);
void * accept_request(void *);
void * proxify(void *data);
void * resolve_request(void *data);
void * finish_request(void *data);
#endif