Apache中的挂钩剖析(2)
日期:2008年3月2日 作者: 查看:[大字体 中字体 小字体]-
5.5.5 挂钩函数(APR_IMPLEMENT_EXTERNAL_HOOK_BASE)从宏的名字我们就可以大体看出该宏实际上是实现了具体的挂钩注册函数,如果将其展开后我们会更加一目了然。该宏的定义也是冗长的很,如下所示:#define APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \const char * const *aszPre, const char * const *aszSucc,int nOrder) \{ \ns##_LINK_##name##_t *pHook; \if(!_hooks.link_##name) \{ \_hooks.link_##name=apr_array_make(apr_hook_global_pool,1,sizeof(ns##_LINK_##name##_t)); \apr_hook_sort_register(#name,&_hooks.link_##name); \} \pHook=apr_array_push(_hooks.link_##name); \pHook->pFunc=pf; \pHook->aszPredecessors=aszPre; \pHook->aszSuccessors=aszSucc; \pHook->nOrder=nOrder; \pHook->szName=apr_hook_debug_current; \if(apr_hook_debug_enabled) \apr_hook_debug_show(#name,aszPre,aszSucc); \} \APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) \{ \return _hooks.link_##name; \}对于post_config挂钩,我们该宏展开的结果如下:AP_DECLARE(int) ap_hook_post_config(ap_HOOK_post_config_t *pf,const char * const *aszPre,const char * const *aszSucc,int nOrder){ap_LINK_post_config_t *pHook;if (!_hooks.link_post_config) {_hooks.link_post_config = apr_array_make(apr_hook_global_pool, 1,sizeof(ap_LINK_post_config_t));apr_hook_sort_register("post_config", &_hooks.link_post_config);}pHook = apr_array_push(_hooks.link_post_config);pHook->pFunc = pf;pHook->aszPredecessors = aszPre;pHook->aszSuccessors = aszSucc;pHook->nOrder = nOrder;pHook->szName = apr_hook_debug_current;if (apr_hook_debug_enabled)apr_hook_debug_show("post_config", aszPre, aszSucc);}AP_DECLARE(apr_array_header_t *) ap_hook_get_post_config(void) {return _hooks.link_post_config;}从上面的展开结果中我们可以很清楚的看出APR_IMPLEMENT_EXTERNAL_HOOK_BASE宏实现了我们所需要的挂钩注册函数以及挂钩信息获取函数。挂钩注册函数中的很多代码非常熟悉,一看原来就是前面我们APR_HOOK_STRUCT中用过的示例代码。挂钩注册函数首先检查挂钩数组是否为空,如果为空则说明是第一次注册该挂钩,所以创建新数组并注册该挂钩类型以供以后排序用;否则,直接加入一条记录。5.5.6 使用挂钩一旦各个模块在挂钩数组中注册了自己感兴趣的挂钩,那么剩下的事情无非就是调用这些挂钩,实际上也就是最终调用挂钩对应的函数。Apache中的挂钩调用函数形式通常如ap_run_HOOKNAME所示,比如ap_run_post_config就是调用post_config挂钩。尽管所有的挂钩对外提供的调用形式都是一样的,但是内部实现却不尽相同,分别体现于三个宏:AP_IMPLEMENT_HOOK_VOID、AP_IMPLEMENT_HOOK_RUN_FIRST以及AP_IMPLEMENT_HOOK_RUN_ALL。(1)、对于AP_IMPLEMENT_HOOK_VOID,调用函数将逐个的调用挂钩数组中的所有的挂钩函数,直到遍历调用结束或者发生错误为止。这种类型通常称之为VOID,是由于其没有任何返回值,其声明如下:#define APR_IMPLEMENT_EXTERNAL_HOOK_VOID(ns,link,name,args_decl,args_use) \APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \link##_DECLARE(void) ns##_run_##name args_decl \{ \ns##_LINK_##name##_t *pHook; \int n; \\if(!_hooks.link_##name) \return; \\pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \pHook[n].pFunc args_use; \}比如对于config.c中的child_init挂钩,其就是VOID类型,声明语句如下:AP_IMPLEMENT_HOOK_VOID(child_init,(apr_pool_t *pchild, server_rec *s),(pchild, s))撇去APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name)不管,这里我们仅仅关心剩下的的展开结果,如下:AP_DECLARE(void) ap_run_child_init(apr_pool_t *pchild,server_rec* s){ap_LINK_child_init_t pHook;int n;if(!_hooks.link_child_init)return;pHook=(ap_LINK_child_init_t)_hooks.link_child_init->elts;for(n=0;n<_hooks.link_child_init->nelts;++n)pHook[n].pFunc(pchild, s);}从展开结果可以看出,即使在逐次调用过程中发生了错误,调用也不会停止,它就是“一头拉不回头的牛”。(2)、AP_IMPLEMENT_HOOK_ALL简称ALL类型,其与AP_IMPLEMENT_HOOK_VOID几乎相同,唯一不同的就是ALL类型具有返回值。宏声明如下:#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \link##_DECLARE(ret) ns##_run_##name args_decl \{ \ns##_LINK_##name##_t *pHook; \int n; \ret rv; \\if(!_hooks.link_##name) \return ok; \\pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \{ \rv=pHook[n].pFunc args_use; \\if(rv != ok && rv != decline) \return rv; \} \return ok; \}open_logs挂钩就是属于这种类型,其在config.c中的定义如下:AP_IMPLEMENT_HOOK_RUN_ALL(int, open_logs,(apr_pool_t *pconf, apr_pool_t *plog,apr_pool_t *ptemp, server_rec *s),(pconf, plog, ptemp, s), OK, DECLINED)因此将它展开后的结果如下:AP_DECLARE(int) ap_run_open_logs(apr_pool_t *pconf, apr_pool_t *plog,apr_pool_t *ptemp, server_rec *s){ap_LINK_open_logs_t *pHook;int n;ret rv;if(!_hooks.link_open_logs)return ok;pHook=(ap_LINK_open_logs_t *)_hooks.link_open_logs->elts; \for(n=0 ; n < _hooks.link_open_logs->nelts ; ++n) \{rv=pHook[n].pFunc(pconf, plog, ptemp, s);if(rv != ok && rv != decline) \return rv;}return ok;}从展开的结果来看,ALL类型在对挂钩数组进行遍历调用的时候,即使调用的请求被“DECLINE”,调用也将继续;只有调用请求发生错误才返回该错误值,同时退出遍历。(3)、AP_IMPLEMENT_HOOK_FIRST简称为FIRST类型,对于该类型Apache核心从头逐一遍历挂钩数组中所注册的挂钩函数,直到遇到一个能够完成所提交任务的函数或者发生错误为止。该宏的定义如下:#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ns,link,ret,name,args_decl,args_use,decline) \APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \link##_DECLARE(ret) ns##_run_##name args_decl \{ \ns##_LINK_##name##_t *pHook; \int n; \ret rv; \\if(!_hooks.link_##name) \return decline; \\pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \{ \rv=pHook[n].pFunc args_use; \\if(rv != decline) \return rv; \} \return decline; \}quick_handler就是属于该类型的挂钩,其在config.c中定义如下:AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup),(r, lookup), DECLINED)该宏展开后的结果如下所示:AP_DECLARE(ret) ap_run_quick_handler(request_rec *r, int lookup){ap_LINK_quick_handler_t *pHook;int n;ret rv;if(!_hooks.link_quick_handler)return decline;pHook=(ap_LINK_quick_handler_t *)_hooks.link_quick_handler->elts;for(n=0 ; n < _hooks.link_quick_handler->nelts ; ++n) \{rv=pHook[n].pFunc(r,look_up);if(rv != decline)return rv;}return decline;}从展开结果中可以看出,在遍历调用过程中一旦找到合适的函数,即rv!=decline的时候,函数即返回,不再继续遍历调用,即使后面仍然有合法的可调用函数。任何挂钩都必须而且只能是三种类型中的一种。任何挂钩在被真正执行之前都必须调用这三个宏中的一个进行声明。5.5.6 编写自己挂钩使用挂钩所带来的最大的一个好处就是可以自行增加挂钩,而不需要全局统一。下面的部分,我们通过编写一个简单的挂钩同时在模块中使用该挂钩从而来加深理解上面所分析的内容。比如现在我们定义在了一个能够在Apache处理请求时调用的函数some_hook,其函数原型为:int some_hook(request_rec* r,int n);那么我们分为四个步骤来声明我们的挂钩。(1)、挂钩声明我们使用AP_DECLARE_HOOK宏声明一个名称为some_hook的挂钩,声明如下:AP_DECLARE_HOOK(int,some_hook,(request_rec* r,int n))(2)、挂钩数组声明由于some_hook是新声明的挂钩,为此,我们必须同时声明新的挂钩数组来保存各个模块对挂钩的注册使用。声明的语句如下:APR_HOOK_STRUCT(APR_HOOK_LINK(some_hook)……)(3)、声明函数调用类型挂钩声明完毕之后,真正被ap_run_name调用之前,我们还必须声明挂钩的调用类型,或者是VOID类型,或者是FIRST类型,或者是ALL类型。此处我们声明some_hook挂钩为VOID类型,声明语句如下:AP_IMPLEMENT_HOOK_RUN_VOID(some_hook,(request_rec* r,int n),(r,n))定义完该宏,实际上也对外声明了该挂钩的执行函数ap_run_some_hook。(4)、注册挂钩函数至第三步为止,对挂钩的声明已经基本结束,也意味着下一步的工作实际上应该落实到挂钩使用者身上了。比如如果模块som_module中想使用挂钩some_hook,则其必须在挂钩注册函数中注册该挂钩,挂钩注册函数为ap_hook_some_hook,代码示例如下:static void register_hooks(){……ap_hook_some_hook(some_hook_function,NULL,NULL,HOOK_MIDDLE);}AP_DECLARE_DATA module core_module = {……register_hooks /* register hooks */};(5)、编写挂钩函数最后剩下的内容就是编写具体的挂钩调用函数。比如在some_module模块中,我们希望挂钩函数只是打印出“Hello World”语句,而且从(4)中看出挂钩函数名称为some_hook_function,因此挂钩函数声明为如下:static void some_hook_function(request_rec* r,int n){ap_rputs(“Hello World\n”);return;}需要注意的是,这边的挂钩函数必须符合AP_IMPLEMENT_HOOK_RUN_XXX中声明的格式。
- [1] [2] 下一页
- Apache中的挂钩剖析(2) 相关文章:
- ·危机重重 2007年度网络安全分析报告
- ·Linux系统网络配置详细解析
- ·诊断和分析提高搜索引擎网站排名
- ·简单分析2007年11月十大网络安全漏洞
- ·简单分析Script脚本跨站攻击漏洞技术
- ·深入分析Windows操作系统死机问题
- ·解析Leopard的备份工具:Time Machine
- ·详细分析操作系统死机的问题
- ·电子杂志的创编制作过程解析
- ·分析Windows操作系统死机问题
- Apache中的挂钩剖析(2) 相关软件
- ·SK魔兽录像分析器 V1.4 Beta 3
- ·文物典藏系列-故宫馆藏文房四宝赏析
- ·中国古籍白话解析系列合集(典藏版V1.1)
- ·《股票常识与技术分析》
- ·大败笔:34个最新的营销失败案例分析
- ·英语迷津-相似词语辨析
- ·金融炼金术:证券分析的逻辑
- ·佳作赏析
- ·股市基本分析
- ·梦的解析
上一篇:要意识到僵尸网络日益增长的威胁
- 特别声明:本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作
- 者.文章版权归文章原始作者所有.对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转
- 载的文章有版权问题请联系编辑人员,我们尽快予以更正. 转载请注明来源:http://www.hackhome.com
精品推荐
热点TOP10
- ·Visual Studio 2005集成开发环境图解
- ·Rational统一过程(1)
- ·Apache APR可移植运行库简介(1)
- ·Tomcat中用web.xml控制Web应用详解
- ·Apache APR可移植运行库简介(3)
- ·Apache中的挂钩剖析(2)
- ·用WPF构建强大的用户体验
- ·软件项目质量管理经验谈
- ·质量功能配置(QFD)
- ·程序员必须注意的十大安全技巧
- ·使用ADO.NET的最佳实践
- ·ISO9000:2000 质量管理八大原则
- ·软件开发管理与质量控制(一)
- ·升级到SQL Server 2005 的10大理由
- ·.NET架构与模式探索
- ·设计.NET应用程序数据访问层五大原则
- ·Visual Studio .NET 中的设计时数据工具
- ·JAVA设计模式之事务处理
- ·Windows工作流活动技术概览
- ·.NET Server 2003中的Microsoft群集服务简介
特别推荐
