mirror of
https://github.com/lxsang/ant-http
synced 2024-11-17 17:08:20 +01:00
feat: rework on plugin support
All checks were successful
gitea-sync/ant-http/pipeline/head This commit looks good
All checks were successful
gitea-sync/ant-http/pipeline/head This commit looks good
- New plugin interface that supports multiple instances - Fix and improve memory bugs - Refactory and cleanup lib - Improve scheduler
This commit is contained in:
parent
3bedc3ffb5
commit
58a7738afe
@ -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 \
|
||||
|
@ -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
|
||||
|
46
config.c
46
config.c
@ -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");
|
||||
}
|
4
decode.c
4
decode.c
@ -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
16
httpd.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
22
lib/handle.c
22
lib/handle.c
@ -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)
|
||||
{
|
||||
|
24
lib/handle.h
24
lib/handle.h
@ -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
51
lib/plugin.c
Normal 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;
|
||||
}
|
78
lib/plugin.h
78
lib/plugin.h
@ -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
18
lib/plugin_ctx.h
Normal 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
|
@ -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;
|
||||
|
@ -1,8 +1,6 @@
|
||||
#ifndef ANT_SCHEDULER
|
||||
#define ANT_SCHEDULER
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
10
lib/utils.c
10
lib/utils.c
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
335
plugin_manager.c
335
plugin_manager.c
@ -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;
|
||||
}
|
||||
|
@ -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
|
55
server.c
55
server.c
@ -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
|
||||
|
8
server.h
8
server.h
@ -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
|
Loading…
Reference in New Issue
Block a user