Lighttpd插件链

Lighttpd插件链

一.    概述

Lighttpd中可以扩展插件增强其功能,插件的框架代码在文件plugin.cplugin.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;

 

三.    插件的加载,方式1

插件的加载主要在函数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

Lighttpd插件链_第1张图片

四.    插件的加载,方式2

在完成了上述的初始化后,又有另一种的初始化的方式,可看函数:

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;

}

五.    插件链表的执行

5.1类似参数(server *srv, connection *con)

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;\

      }

5.2类似参数(server *srv)

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)

 

你可能感兴趣的:(Lighttpd插件链)