Lighttpd中可以扩展插件增强其功能,插件的框架代码在文件plugin.c和plugin.h中。
2.1
typedef struct {
size_tversion;
buffer*name; /* name of the plugin */
void*(* init) ();
handler_t(* set_defaults) (server *srv,void *p_d);
handler_t(* cleanup) (server *srv,void *p_d);
/* is called ... */
handler_t(* handle_trigger) (server *srv,void *p_d); /* once asecond */
handler_t(* handle_sighup) (server *srv,void *p_d); /* at asignup */
handler_t(* handle_uri_raw) (server *srv,connection *con, void *p_d); /* afteruri_raw is set */
handler_t(* handle_uri_clean) (server *srv,connection *con, void *p_d); /* afteruri is set */
handler_t(* handle_docroot) (server *srv,connection *con, void *p_d); /*getting the document-root */
handler_t(* handle_physical) (server *srv,connection *con, void *p_d); /*mapping url to physical path */
handler_t(* handle_request_done) (server *srv,connection *con, void *p_d); /* at theend of a request */
handler_t(* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */
handler_t(* handle_joblist) (server *srv,connection *con, void *p_d); /* afterall events are handled */
handler_t(* handle_subrequest_start)(server *srv, connection *con, void *p_d);
handler_t(* handle_subrequest) (server *srv,connection *con, void *p_d); /* */
handler_t(* connection_reset) (server *srv,connection *con, void *p_d); /* */
void*data;
void*lib;
} plugin;
2.2
typedef enum {
PLUGIN_FUNC_UNSET,
PLUGIN_FUNC_HANDLE_URI_CLEAN,
PLUGIN_FUNC_HANDLE_URI_RAW,
PLUGIN_FUNC_HANDLE_REQUEST_DONE,
PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
PLUGIN_FUNC_HANDLE_TRIGGER,
PLUGIN_FUNC_HANDLE_SIGHUP,
PLUGIN_FUNC_HANDLE_SUBREQUEST,
PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
PLUGIN_FUNC_HANDLE_JOBLIST,
PLUGIN_FUNC_HANDLE_DOCROOT,
PLUGIN_FUNC_HANDLE_PHYSICAL,
PLUGIN_FUNC_CONNECTION_RESET,
PLUGIN_FUNC_INIT,
PLUGIN_FUNC_CLEANUP,
PLUGIN_FUNC_SET_DEFAULTS,
PLUGIN_FUNC_SIZEOF
} plugin_t;
插件的加载主要在函数int plugins_load(server*srv)中完成;在系统启动过程中,已经读取了配置文件,得到了要加载的插件名称,因此根据此名称可以打开相应的动态链接文件,取得其初始化函数,执行,然后定义该插件。
int plugins_load(server *srv)
{
plugin*p;
int(*init)(plugin *pl);
constchar *error;
size_ti, j;
for(i = 0; i < srv->srvconf.modules->used; i++) {
data_string*d = (data_string *)srv->srvconf.modules->data[i];
char*modules = d->value->ptr;
for(j = 0; j < i; j++) {
if(buffer_is_equal(d->value, ((data_string *)srv->srvconf.modules->data[j])->value)) {
log_error_write(srv,__FILE__, __LINE__, "sbs", "Cannot load plugin",d->value, "more than once, please fix your config (we may not acceptsuch configs in future releases");
continue;
}
}
buffer_copy_string_buffer(srv->tmp_buf,srv->srvconf.modules_dir);
buffer_append_string_len(srv->tmp_buf,CONST_STR_LEN("/"));
buffer_append_string(srv->tmp_buf,modules);
buffer_append_string_len(srv->tmp_buf,CONST_STR_LEN(".so"));//取得插件名称
p= plugin_init(); //为插件定义空间
if(NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
log_error_write(srv,__FILE__, __LINE__, "sbs", "dlopen() failed for:",
srv->tmp_buf,dlerror());
plugin_free(p);
return-1;
}
buffer_reset(srv->tmp_buf);
buffer_copy_string(srv->tmp_buf,modules);
buffer_append_string_len(srv->tmp_buf,CONST_STR_LEN("_plugin_init"));
#if 1
init= (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
#else
*(void**)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
#endif
if((error = dlerror()) != NULL) {
log_error_write(srv,__FILE__, __LINE__, "s", error);
plugin_free(p);
return-1;
}
if((*init)(p)) {//执行插件的初始化函数,为p定义各个函数指针。
log_error_write(srv,__FILE__, __LINE__, "ss", modules, "plugin init failed" );
plugin_free(p);
return-1;
}
plugins_register(srv, p); //将初始化完成的p,赋值给srv->plugins
}
return0;
}
#endif
该函数执行完后,各插件在内存中具有这样的结构:
Typedeft struct server
{
。。。。。。
buffer_pluginplugins;
。。。。。。
}
typedef struct {
void *ptr;
size_tused;
size_tsize;
} buffer_plugin;
假设定义了三个插件,mod_cgi,mod_fastcgi, mod_ssi,所以这三个插件就在数组srv->plugins.ptr中
在完成了上述的初始化后,又有另一种的初始化的方式,可看函数:
handler_t plugins_call_init(server *srv),在
Typedeft struct server
{
。。。。。。
void *plugin_slots;
。。。。。。
}
序号 |
Plugin_slots |
|
|
|
|
1 |
PLUGIN_FUNC_HANDLE_URI_CLEAN, |
Mod_ssi |
Mod_cgi |
|
|
2 |
PLUGIN_FUNC_HANDLE_URI_RAW, |
|
|
|
|
3 |
|
|
|
|
|
4 |
|
|
|
|
|
5 |
|
|
|
|
|
6 |
|
|
|
|
|
7 |
|
|
|
|
|
8 |
|
|
|
|
|
9 |
PLUGIN_FUNC_HANDLE_JOBLIST |
|
|
|
|
10 |
PLUGIN_FUNC_HANDLE_DOCROOT |
Mod_cgi |
Mod_fastcgi |
|
|
11 |
PLUGIN_FUNC_HANDLE_PHYSICAL |
|
|
|
|
具体如下:
handler_t plugins_call_init(server *srv)
{
size_ti;
plugin**ps;
ps= srv->plugins.ptr;
/*fill slots */
srv->plugin_slots= calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
// PLUGIN_FUNC_SIZEOF,为插件所具有的函数的个数
for(i = 0; i < srv->plugins.used; i++) {
size_tj;
/*check which calls are supported */
plugin*p = ps[i];
#define PLUGIN_TO_SLOT(x, y) \
if(p->y) { \
plugin**slot = ((plugin ***)(srv->plugin_slots))[x]; \
if(!slot) { \
slot= calloc(srv->plugins.used, sizeof(*slot));\
((plugin***)(srv->plugin_slots))[x] = slot; \
}\
for(j = 0; j < srv->plugins.used; j++) { \
if(slot[j]) continue;\
slot[j]= p;\
break;\
}\
}
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN,handle_uri_clean);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW,handle_uri_raw);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE,handle_request_done);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,handle_connection_close);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER,handle_trigger);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP,handle_sighup);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST,handle_subrequest);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START,handle_subrequest_start);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST,handle_joblist);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT,handle_docroot);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL,handle_physical);
PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET,connection_reset);
PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP,cleanup);
PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS,set_defaults);
#undef PLUGIN_TO_SLOT
if(p->init) {
if(NULL == (p->data = p->init())) {
log_error_write(srv,__FILE__, __LINE__, "sb",
"plugin-initfailed for module", p->name);
returnHANDLER_ERROR;
}
/*used for con->mode, DIRECT == 0, plugins above that */
((plugin_data*)(p->data))->id = i + 1; //以后会根据该值判断某个连接是否需要执行该插件
if(p->version != LIGHTTPD_VERSION_ID) {
log_error_write(srv,__FILE__, __LINE__, "sb",
"plugin-versiondoesn't match lighttpd-version for", p->name);
returnHANDLER_ERROR;
}
}else {
p->data= NULL;
}
}
returnHANDLER_GO_ON;
}
handler_tplugins_call_handle_uri_raw(server *srv, connection *con);
handler_tplugins_call_handle_uri_clean(server *srv, connection *con);
handler_tplugins_call_handle_subrequest_start(server *srv, connection *con);
handler_tplugins_call_handle_subrequest(server *srv, connection *con);
handler_tplugins_call_handle_request_done(server *srv, connection *con);
handler_t plugins_call_handle_docroot(server*srv, connection *con);
handler_tplugins_call_handle_physical(server *srv, connection *con);
handler_tplugins_call_handle_connection_close(server *srv, connection *con);
handler_tplugins_call_handle_joblist(server *srv, connection *con);
handler_tplugins_call_connection_reset(server *srv, connection *con);
#define PLUGIN_TO_SLOT(x, y) \
handler_tplugins_call_##y(server *srv, connection *con) {\
plugin**slot;\
size_tj;\
if (!srv->plugin_slots)return HANDLER_GO_ON;\
slot = ((plugin***)(srv->plugin_slots))[x];\
if(!slot) return HANDLER_GO_ON;\
for(j = 0; j < srv->plugins.used && slot[j]; j++) { \
plugin*p = slot[j];\
handler_tr;\
switch(r= p->y(srv, con, p->data)) {\
caseHANDLER_GO_ON:\
break;\
caseHANDLER_FINISHED:\
caseHANDLER_COMEBACK:\
caseHANDLER_WAIT_FOR_EVENT:\
caseHANDLER_WAIT_FOR_FD:\
caseHANDLER_ERROR:\
returnr;\
default:\
log_error_write(srv,__FILE__, __LINE__, "sbs", #x, p->name, "unknownstate");\
returnHANDLER_ERROR;\
}\
}\
returnHANDLER_GO_ON;\
}
handler_tplugins_call_handle_trigger(server *srv);
handler_t plugins_call_handle_sighup(server*srv);
handler_t plugins_call_init(server *srv);
handler_t plugins_call_set_defaults(server*srv);
handler_t plugins_call_cleanup(server*srv);
#define PLUGIN_TO_SLOT(x, y) \
handler_tplugins_call_##y(server *srv) {\
plugin**slot;\
size_tj;\
if (!srv->plugin_slots)return HANDLER_GO_ON;\
slot = ((plugin***)(srv->plugin_slots))[x];\
if(!slot) return HANDLER_GO_ON;\
for(j = 0; j < srv->plugins.used && slot[j]; j++) { \
plugin*p = slot[j];\
handler_tr;\
switch(r= p->y(srv, p->data)) {\
caseHANDLER_GO_ON:\
break;\
caseHANDLER_FINISHED:\
caseHANDLER_COMEBACK:\
caseHANDLER_WAIT_FOR_EVENT:\
caseHANDLER_WAIT_FOR_FD:\
caseHANDLER_ERROR:\
returnr;\
default:\
log_error_write(srv,__FILE__, __LINE__, "sbsd", #x, p->name, "unknownstate:", r);\
returnHANDLER_ERROR;\
}\
}\
returnHANDLER_GO_ON;\
}
插件链表在函数handler_thttp_response_prepare(server *srv, connection *con)中调用最多:
plugins_call_handle_uri_raw(srv, con)
plugins_call_handle_uri_clean(srv, con)
plugins_call_handle_docroot(srv, con)
plugins_call_handle_physical(srv, con)
plugins_call_handle_subrequest_start(srv,con)
plugins_call_handle_subrequest(srv, con)