1
0
mirror of https://github.com/lxsang/ant-http synced 2024-06-14 22:30:14 +02:00

feat: rework on plugin support
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:
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/sha1.c \
lib/list.c \ lib/list.c \
lib/bst.c \ lib/bst.c \
lib/scheduler.c lib/scheduler.c \
lib/plugin.c
pkginclude_HEADERS = lib/ini.h \ pkginclude_HEADERS = lib/ini.h \
lib/handle.h \ lib/handle.h \

View File

@ -3,8 +3,6 @@
plugins=/opt/www/lib/ plugins=/opt/www/lib/
; plugin extension ; plugin extension
plugins_ext=.so plugins_ext=.so
; SQLITE database path
database=/opt/www/database/
; tmp dir ; tmp dir
tmpdir=/opt/www/tmp/ tmpdir=/opt/www/tmp/
; max concurent connection ; 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)) if (value && (strncmp(value, "1", 1) == 0 || strncmp(value, "true", 3) == 0))
{ {
// load the plugin // load the plugin
LOG("Plugin %s: autoloading...", it->key); LOG("Plugin %s: auto loading...", it->key);
plugin_load(it->key, config); 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); free(pconfig->plugins_ext);
pconfig->plugins_ext = strdup(value); 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")) else if (MATCH("SERVER", "tmpdir"))
{ {
if (stat(value, &st) == -1) 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);*/ LOG("SSL Cipher suite: %s", g_server_config.ssl_cipher);*/
#endif #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); LOG("%d mimes entries found", g_server_config.mimes->size);
// Init plugins if necessary // Init plugins if necessary
init_plugins(); init_plugins();
@ -361,9 +351,17 @@ void destroy_config()
if (g_server_config.ssl_cipher) if (g_server_config.ssl_cipher)
free(g_server_config.ssl_cipher); free(g_server_config.ssl_cipher);
if (g_server_config.gzip_types) if (g_server_config.gzip_types)
{
list_free(&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) if (g_server_config.mimes)
{
freedict(g_server_config.mimes); freedict(g_server_config.mimes);
set_mimes_list(NULL);
}
if (g_server_config.stat_fifo_path) if (g_server_config.stat_fifo_path)
free(g_server_config.stat_fifo_path); free(g_server_config.stat_fifo_path);
if (g_server_config.plugins) if (g_server_config.plugins)
@ -371,9 +369,18 @@ void destroy_config()
for_each_assoc(it, g_server_config.plugins) for_each_assoc(it, g_server_config.plugins)
{ {
freedict((dictionary_t)it->value); freedict((dictionary_t)it->value);
it->value = NULL;
} }
freedict(g_server_config.plugins); 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) if (g_server_config.ports)
{ {
port_config_t *cnf; port_config_t *cnf;
@ -396,4 +403,5 @@ void destroy_config()
freedict(g_server_config.ports); freedict(g_server_config.ports);
} }
LOG("Unclosed connection: %d", g_server_config.connection); 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) if (!ret)
{ {
free(task);
return NULL; return NULL;
} }
@ -367,7 +368,7 @@ void *decode_request_header(void *data)
dictionary_t request = dvalue(rq->request, "REQUEST_DATA"); dictionary_t request = dvalue(rq->request, "REQUEST_DATA");
char *port_s = (char *)dvalue(rq->request, "SERVER_PORT"); char *port_s = (char *)dvalue(rq->request, "SERVER_PORT");
port_config_t *pcnf = (port_config_t *)dvalue(g_server_config.ports, port_s); 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 // first real all header
// this for check if web socket is enabled // 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 // 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); // 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"); antd_error(rq->client, 400, "Bad Request, missing content data");
return task; return task;
} }

16
httpd.c
View File

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

View File

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

View File

@ -100,11 +100,31 @@ int require_plugin(const char *name)
return 0; 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) 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; return 0;
} }
#endif
const char *get_status_str(int stat) const char *get_status_str(int stat)
{ {

View File

@ -5,6 +5,7 @@
#include "list.h" #include "list.h"
#include "dictionary.h" #include "dictionary.h"
#include "plugin.h"
#define SERVER_NAME "Antd" #define SERVER_NAME "Antd"
#define IS_POST(method) (strcmp(method, "POST") == 0) #define IS_POST(method) (strcmp(method, "POST") == 0)
@ -28,9 +29,6 @@
#define ANTD_CLIENT_RQ_DATA_DECODE 0x7 #define ANTD_CLIENT_RQ_DATA_DECODE 0x7
#define ANTD_CLIENT_PROXY_MONITOR 0x8 #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 #define MAX_PATH_LEN 256
typedef enum typedef enum
@ -63,6 +61,7 @@ typedef struct
{ {
antd_client_t *client; antd_client_t *client;
dictionary_t request; dictionary_t request;
antd_plugin_ctx_t * context;
} antd_request_t; } antd_request_t;
typedef struct typedef struct
@ -73,23 +72,12 @@ typedef struct
} antd_response_header_t; } 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_nonblock(int socket);
//void set_block(int socket); //void set_block(int socket);
#ifdef USE_ZLIB
int __attribute__((weak)) compressable(char *ctype); int compressable(char *ctype);
void set_gzip_types(list_t list);
#endif
void antd_send_header(void *, antd_response_header_t *); void antd_send_header(void *, antd_response_header_t *);
const char *get_status_str(int stat); const char *get_status_str(int stat);
int __t(void *, const char *, ...); 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 #ifndef PLUGIN_H
#define PLUGIN_H #define PLUGIN_H
#include <sys/stat.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 "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(); typedef struct _plugin_ctx_t antd_plugin_ctx_t;
/*Default function for plugin*/
// init the plugin
void init();
void destroy();
void* handle(void*);
plugin_header_t* meta();
void use_raw_body();
/* const char *antd_plugin_basedir(antd_plugin_ctx_t *);
STATIC PART, should be included in any plugin const char *antd_plugin_tmpdir(antd_plugin_ctx_t *);
*/ const char *antd_plugin_confdir(antd_plugin_ctx_t *);
#ifdef PLUGIN_IMPLEMENT 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,...) \ /*Default interfaces shall be implemented by plugin*/
ERROR("%s: "a,__plugin__.name, ##__VA_ARGS__); \ void *create(antd_plugin_ctx_t *);
__plugin__.status = ANTD_PLUGIN_PANNIC; 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 #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 *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->stamp = (unsigned long)time(NULL);
task->data = data; task->data = data;
task->handle = handle; task->handle = handle;

View File

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

View File

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

View File

@ -34,6 +34,7 @@ THE SOFTWARE.
#include "dictionary.h" #include "dictionary.h"
#define STRINGIFY(x) #x
#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) #define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
#define EQU(a,b) (strcmp(a,b) == 0) #define EQU(a,b) (strcmp(a,b) == 0)
#define IEQU(a,b) (strcasecmp(a,b) == 0) #define IEQU(a,b) (strcasecmp(a,b) == 0)
@ -44,9 +45,9 @@ THE SOFTWARE.
#define true 1 #define true 1
#define false 0 #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__) __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__) __LINE__, ##__VA_ARGS__)
// add this to the utils // add this to the utils
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
@ -65,7 +66,8 @@ typedef union
struct sockaddr_in addr4; struct sockaddr_in addr4;
} antd_sockaddr_t; } antd_sockaddr_t;
dictionary_t __attribute__((weak)) mimes_list(); dictionary_t mimes_list();
void set_mimes_list(dictionary_t);
char* __s(const char*,...); char* __s(const char*,...);
void trim(char*,const char); void trim(char*,const char);
void removeAll(const char* path,int mode); void removeAll(const char* path,int mode);

View File

@ -5,16 +5,21 @@
#include <sys/sendfile.h> #include <sys/sendfile.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include "plugin_manager.h"
#include "lib/utils.h" #include "lib/utils.h"
#include "lib/handle.h" #include "lib/handle.h"
#include "config.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; 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 * Plugin table to store the loaded plugin
*/ */
@ -25,8 +30,12 @@ static struct plugin_entry *plugin_table[HASHSIZE];
* @param s plugin name * @param s plugin name
* @return a plugin entry in the plugin table * @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; struct plugin_entry *np;
for (np = plugin_table[hash(s, HASHSIZE)]; np != NULL; np = np->next) for (np = plugin_table[hash(s, HASHSIZE)]; np != NULL; np = np->next)
if (strcmp(s, np->name) == 0) if (strcmp(s, np->name) == 0)
@ -34,6 +43,136 @@ struct plugin_entry *plugin_lookup(char *s)
return NULL; /* not found */ 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 * Load a plugin to the plugin table
* Only load when not available in 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 * @param config: plugin configuration
* @return pointer to the loaded plugin * @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]; char path[BUFFLEN];
struct plugin_entry *np; struct plugin_entry *np;
unsigned hashval; unsigned hashval;
plugin_header_t *(*metafn)(); antd_plugin_ctx_t *ctx;
plugin_header_t *meta = NULL; dictionary_t pconf = dvalue(g_server_config.plugins, name);
int fromfd, tofd;
char *error;
struct stat st;
int is_tmp = 0;
if (pconf) 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 */ { /* not found */
LOG("Loading plugin: %s...", name); LOG("Loading plugin: %s...", plugin_file_name);
np = (struct plugin_entry *)malloc(sizeof(*np)); np = (struct plugin_entry *)malloc(sizeof(struct plugin_entry));
if (np == NULL || name == NULL) np->instances = NULL;
if (np == NULL)
{ {
if (np)
free(np);
return NULL; return NULL;
} }
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, name, g_server_config.plugins_ext); (void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, plugin_file_name, g_server_config.plugins_ext);
if (pname && strcmp(name, pname) != 0) 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 ERROR("Cannot load plugin '%s' : '%s'", plugin_file_name, dlerror());
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, pname, g_server_config.plugins_ext); antd_plugin_entry_drop(np);
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);
return NULL; return NULL;
} }
np->instances = dict();
hashval = hash(name, HASHSIZE); hashval = hash(name, HASHSIZE);
np->next = plugin_table[hashval]; np->next = plugin_table[hashval];
plugin_table[hashval] = np; plugin_table[hashval] = np;
} }
else /* already there */ 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 // check if plugin is ready
metafn = (plugin_header_t * (*)()) dlsym(np->handle, "meta"); if (ctx == NULL)
if ((error = dlerror()) != NULL)
{ {
ERROR("Unable to fetch plugin meta-data: [%s] %s", name, error); ERROR("Unable to fetch plugin context for: [%s] %s", plugin_file_name, name);
unload_plugin_by_name(name);
free(np);
return NULL; return NULL;
} }
meta = metafn(); LOG("PLugin instance status: [%s] %d", name, ctx->status);
LOG("PLugin status: [%s] %d", name, meta->status); if (ctx->status != ANTD_PLUGIN_READY)
if (!meta || meta->status != ANTD_PLUGIN_READY)
{ {
ERROR("Plugin is not ready or error: [%s].", name); ERROR("Plugin instance is not ready or error: [%s].", name);
unload_plugin_by_name(name); antd_plugin_ctx_drop(np, ctx);
free(np);
return NULL; return NULL;
} }
return np; return ctx;
}
/**
* 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;
} }
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 Unload a plugin by its name
*/
void unload_plugin_by_name(const char *name) void unload_plugin_by_name(const char *name)
{ {
struct plugin_entry *np; struct plugin_entry *np;
@ -212,7 +257,7 @@ void unload_plugin_by_name(const char *name)
np = plugin_table[hasval]; np = plugin_table[hasval];
if (strcmp(np->name, name) == 0) if (strcmp(np->name, name) == 0)
{ {
unload_plugin(np); antd_plugin_entry_drop(np);
plugin_table[hasval] = np->next; plugin_table[hasval] = np->next;
} }
else else
@ -226,14 +271,16 @@ void unload_plugin_by_name(const char *name)
} }
if (np == NULL) if (np == NULL)
return; // the plugin is is not loaded return; // the plugin is is not loaded
unload_plugin(np->next); antd_plugin_entry_drop(np->next);
np->next = np->next->next; np->next = np->next->next;
} }
} }
*/
/** /**
* Unload all the plugin loaded on the plugin table * Unload all the plugin loaded on the plugin table
*/ */
void unload_all_plugin() void antd_unload_all_plugin()
{ {
LOG("Unload all plugins"); LOG("Unload all plugins");
for (int i = 0; i < HASHSIZE; i++) for (int i = 0; i < HASHSIZE; i++)
@ -244,10 +291,14 @@ void unload_all_plugin()
while ((curr = *np) != NULL) while ((curr = *np) != NULL)
{ {
(*np) = (*np)->next; (*np) = (*np)->next;
unload_plugin(curr); antd_plugin_entry_drop(curr);
free(curr); //free(curr);
} }
plugin_table[i] = NULL; 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 #define PLUGIN_MANAGER_H
#include "lib/dictionary.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 { antd_plugin_ctx_t *antd_plugin_load(const char *name);
struct plugin_entry *next; void antd_unload_all_plugin();
char *name; antd_plugin_handle_t antd_get_ctx_handle(antd_plugin_ctx_t *);
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*);
#endif #endif

View File

@ -3,7 +3,6 @@
#endif #endif
#include <sys/socket.h> #include <sys/socket.h>
#include <poll.h> #include <poll.h>
#include <dlfcn.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
@ -534,13 +533,8 @@ void *proxify(void *data)
*/ */
void *execute_plugin(void *data, const char *pname) 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]; char pattern[256];
antd_plugin_ctx_t* ctx;
antd_request_t *rq = (antd_request_t *)data; 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_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); 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; rq->client->state = ANTD_CLIENT_PLUGIN_EXEC;
// load the plugin // load the plugin
pthread_mutex_lock(&server_mux); 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); pthread_mutex_unlock(&server_mux);
if (plugin == NULL) if (ctx == NULL)
{ {
antd_error(rq->client, 503, "Requested service not found"); antd_error(rq->client, 503, "Requested service not found");
return task; return task;
} }
// check if the plugin want rawbody or decoded body rq->context = ctx;
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;
}
// check if we need the raw data or not // 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 else
{ {
free(task); 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; 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 #ifndef HTTP_SERVER
#define HTTP_SERVER #define HTTP_SERVER
void *accept_request(void *); void * accept_request(void *);
void *proxify(void *data); void * proxify(void *data);
void *resolve_request(void *data); void * resolve_request(void *data);
void *finish_request(void *data); void * finish_request(void *data);
#endif #endif