当前位置: 首页 >> 应用软件 >> 网络相关 >> Apache中的挂钩剖析(3)
 

Apache中的挂钩剖析(3)

作者:flydish1234 at sina.com.cn      来源:     发表时间:2006-03-06     浏览次数:      字号:    

5.5.7 可选挂钩
与标准挂钩相比,可选挂钩基本上没有太大的差异,唯一的区别就在于可选挂钩不一定需要被实现——这看起来令人迷惑的。不过你很快就会明白了。考虑一下,如果某个挂钩Hook_A是声明在一个可选模块中,那么正常情况下该模块没有被加载。如此此时某个模块想使用挂钩Hook_A,那么会发生什么情况呢。对于标准模块,Apache可能根本就无法进行编译。而可选挂钩则可以解决这种问题。对于可选挂钩,即使它没有被导入并运行,其余的模块也可以使用它。
可选挂钩的声明方法与标准挂钩声明没有任何区别,都是通过AP_DECLARE_HOOK进行的,比如下面的语句声明一个可选挂钩:
AP_DECLARE_HOOK(int , optional_hook , (request_rec *r , int n))
与标准挂钩相比,可选挂钩没有内部私有的数据结构。在标准挂钩中,为了保存各个模块对声明的挂钩的使用情况,通过声明AP_HOOK_STRUCT结构来实现。这种做法实际上是由挂钩实现者自行进行维护;而对于可选挂钩,模块编写者可以不需要维护该AP_HOOK_STRUCT结构了,该结构则转交内核维护。
在实现上,可选挂钩的声明从标准挂钩的AP_IMPLEMENT_HOOK_RUN_ALL形式转变为AP_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL
5.5.7.1可选挂钩数组
在Apache2.0中,任何模块对可选挂钩的调用信息都由Apache核心进行维护。在Apache内部,核心定义了两个全局哈希表s_phOptionalHooks和s_phOptionalFunctions分别保存所有的可选挂钩以及对应的挂钩处理句柄。S_phOptionalHooks哈希表中,可选挂钩名称用来作为哈希表Key键,而挂钩对应的挂钩数组则作为哈希表的Value值。其结构如上图所示。在Apr_hooks.c中,Apache提供了两个支持函数:apr_optional_hook_get和apr_optional_hook_add。

apr_optional_hook_get函数用来在哈希表s_phOptionalHooks中查找指定挂钩的挂钩数组,如果找到了则返回数组;否则返回NULL。
apr_optional_hook_add函数的原型声明如下:
APU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
                    const char * const *aszPre,
                    const char * const *aszSucc,int nOrder)
该函数主要在可选挂钩szName数组中,增加一个登记项,登记的挂钩函数为pfn。同时aszPre、aszSucc以及nOrder与标准挂钩的含义相同。
在登记之前,函数必须能够在哈希表中找到挂钩szName对应的挂钩数组,这个可以通过apr_optional_hook_get来完成。由于可选挂钩可以没有任何挂钩函数,因此上图中挂钩数组为NULL也是可能的,此时必须为该挂钩首先生成挂钩数组,将该挂钩数组在哈希表中与键szName关联起来,同时进行排序。
如果szName挂钩数组已经存在,则直接调用apr_array_push相关信息压入数组并赋值。
可选挂钩数组中每个元素的结构都是apr_LINK__optional_t类型,其是宏APR_DECLARE_EXTERNAL_HOOK展开的结果,apr_LINK__optional_t结构实际如下所示:
typedef struct ap_LINK_optional_t
    {
         ap_HOOK_optional_t *pFunc;
         const char *szName;
         const char * const *aszPredecessors;
         const char * const *aszSuccessors;
         int nOrder;
    } ap_LINK_optional_t;
 
5.5.7.2 声明可选挂钩(APR_OPTIONAL_HOOK)
对于标准挂钩,注册使用挂钩通常使用ap_hook_name之类的函数,这些函数最终将使用信息登记到挂钩数组中去。而对于可选挂钩,由于不存在AP_HOOK_STRUCT宏,因此也就不存在挂钩数组了。在前面我们提到过,可选挂钩的保存是由Apache内核维护的,我们展开宏APR_OPTIONAL_HOOK就知道了。
APR_OPTIONAL_HOOK宏定义在ap_optional_hooks.h中:
#define APR_OPTIONAL_HOOK(ns,name,pfn,aszPre,aszSucc,nOrder) do { \
 ns##_HOOK_##name##_t *apu__hook = pfn; \
 apr_optional_hook_add(#name,(void (*)(void))apu__hook,aszPre, aszSucc, nOrder); \
} while (0)
 
5.5.7.3 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL
对于标准挂钩,其实现分为VOID、FIRST和ALL三种,而对于可选挂钩,实现则归结只有一种ALL类型,即APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL,该宏定义如下:
#define APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \
link##_DECLARE(ret) ns##_run_##name args_decl \
    { \
    ns##_LINK_##name##_t *pHook; \
    int n; \
    ret rv; \
    apr_array_header_t *pHookArray=apr_optional_hook_get(#name); \
    if(!pHookArray) \
     return ok; \
    pHook=(ns##_LINK_##name##_t *)pHookArray->elts; \
    for(n=0 ; n < pHookArray->nelts ; ++n) \
     { \
     rv=(pHook[n].pFunc)args_use; \
\
     if(rv != ok && rv != decline) \
         return rv; \
     } \
    return ok; \
    }
status模块mod_status.c中我们声明的挂钩status_hook就是一个可选挂钩,该挂钩实现如下:
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook,
                                    (request_rec *r, int flags),
                  &n

[1] [2] [3]

编辑 webmaster

 
 
 
评论更多>>
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •