转自:http://www.cnblogs.com/kernel_hcy/archive/2010/03/11/1683814.html
if (plugins_load(srv)) { log_error_write(srv, __FILE__, __LINE__, "s","loading plugins finally failed"); plugins_free(srv); server_free(srv); return -1; }
#ifdef LIGHTTPD_STATIC int plugins_load(server * srv) { plugin *p; #define PLUGIN_INIT(x)\ p = plugin_init(); \ if (x ## _plugin_init(p)) { \ log_error_write(srv, __FILE__, __LINE__, "ss",#x, "plugin init failed" ); \ plugin_free(p); \ return -1;\ }\ plugins_register(srv, p); #include "plugin-static.h" return 0; } #else //动态链接 int plugins_load(server * srv) { plugin *p; int (*init) (plugin * pl); const char *error; size_t i; for (i = 0; i < srv->srvconf.modules->used; i++) { //获得动态链接库的名称。 data_string *d = (data_string *) srv->srvconf.modules->data[i]; char *modules = d->value->ptr; //库所在目录 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(); //linux调用函数dlopen加载动态库 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; } //调用动态库中的XXX_plugin_init函数。 //XXX是库的名称 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 //调用dlsym函数获得XXX_plugin_init函数的地址。 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; } //初始化插件 //在初始化的过程中,模块将自己所有的对外接口函数的入口地址都存入到p中。 if ((*init) (p)) { log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed"); plugin_free(p); return -1; } #if 0 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded"); #endif plugins_register(srv, p); } return 0; } #endif //end of #ifdef LIGHTTPD_STATIC
int mod_cgi_plugin_init(plugin * p)
{
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("cgi");
p->connection_reset = cgi_connection_close_callback;
p->handle_subrequest_start = cgi_is_handled;
p->handle_subrequest = mod_cgi_handle_subrequest;
#if 0
p->handle_fdevent = cgi_handle_fdevent;
#endif
p->handle_trigger = cgi_trigger;
p->init = mod_cgi_init;
p->cleanup = mod_cgi_free;
p->set_defaults = mod_fastcgi_set_defaults;
p->data = NULL;
return 0;
}
if (HANDLER_GO_ON != plugins_call_init(srv))
{
log_error_write(srv, __FILE__, __LINE__, "s",
"Initialization of plugins failed. Going down.");
plugins_free(srv);
network_close(srv);
server_free(srv);
return -1;
}
handler_t plugins_call_init(server * srv) { size_t i; plugin **ps; ps = srv->plugins.ptr; /* * fill slots */ srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps)); for (i = 0; i < srv->plugins.used; i++) { size_t j; /* * check which calls are supported */ plugin *p = ps[i]; /** * 对所有的plugin进行登记造册。这个宏在后文中着重讲解。 */ #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-init failed for module", p->name); return HANDLER_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-version doesn't match lighttpd-version for", p->name); return HANDLER_ERROR; } } else { p->data = NULL; } } return HANDLER_GO_ON; }整个函数中,这个宏是重点:
#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;\ }\ }
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;
INIT_FUNC(mod_cgi_init) { plugin_data *p; p = calloc(1, sizeof(*p)); assert(p); p->tmp_buf = buffer_init(); p->parse_response = buffer_init(); return p; }