本文在上文《Apache Hook机制解析(上)——钩子机制的实现》的基础上,对钩子机制的细节了补充分析。

1.    静态变量_hooks
这个变量由宏APR_HOOK_STRUCT所定义,因为是静态的,所以对这个变量的操作只能在同一源文件中实现——也对应的AP_IMPLEMENT_HOOK_RUN_ALL宏必须在APR_HOOK_STRUCT所在的源文件中被定义。

2.    AP__开头的宏和APR__开头的宏
APR指Apache Portable Runtime,它是一个基本的库,可以用于Apache HTTP Server,也可用于其他产品;而AP实际上指Apache HTTP Server。

因此AP__开头的宏很多都是对APR__宏的进一层封装,将其封装到Apache HTTP Server的命名空间,如AP_IMPLEMENT_HOOK_RUN_ALL实际上是APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL宏的封装:

#define AP_IMPLEMENT_HOOK_RUN_ALL(ret,name,args_decl,args_use,ok,decline) /
    APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap,AP,ret,name,args_decl, /
                                            args_use,ok,decline)

如果是要在自己写的代码中调用APR库,则必须使用APR__开头的宏。

3.    AP_IMPLEMENT_HOOK_RUN_ALL的变种
在apr_hooks.h中的代码中可以看到,除了AP_IMPLEMENT_HOOK_RUN_ALL宏之外,还有两个用于定义钩子的宏:
APR_IMPLEMENT_EXTERNAL_HOOK_VOID
AP_IMPLEMENT_HOOK_RUN_FIRST

第一个宏是为了无参数的钩子函数准备的,对应前面log_transaction的例子,该宏展开后的触发函数代码如下:
AP_DECALRE(void) ap_run_log_transaction (request_rec *r)
{
    ap_AP_log_transaction_t *pHook;
    int n;

if(!_hooks.link_log_transaction)
    return ok;

pHook=(ap_AP_log_transaction_t *)_hooks.link_log_transaction->elts;
    for(n=0 ; n < _hooks.link_log_transaction->nelts ; ++n)
        pHook[n].pFunc (r);
}

第二个宏用于执行条件触发——如果某些钩子实现返回了DECLINE(拒绝),则停止执行后续的钩子函数。对应前面log_transaction的例子,该宏展开后的触发函数代码如下:
AP_DECALRE(int) ap_run_log_transaction (request_rec *r)
{
    ap_AP_log_transaction_t *pHook;
    int n;
    ret rv;

if(!_hooks.link_log_transaction)
    return decline;

pHook=(ap_AP_log_transaction_t *)_hooks.link_log_transaction->elts;
    for(n=0 ; n < _hooks.link_log_transaction->nelts ; ++n)
    {
        rv=pHook[n].pFunc (r);

if(rv != decline)
            return rv;
    }
    return decline;
}

这里的实现和AP_IMPLEMENT_HOOK_RUN_ALL 不同主要在于:
1)    默认的返回是decline,而不是ok
2)    只要钩子函数返回decline,则终止循环

4.    ap_hook_get_log_transaction
进行钩子的声明和定义时,除了ap_hook_ log_transaction和ap_run_ log_transaction,还有一个函数——ap_hook_get_log_transaction。

这个函数的用处只是提供给外界一个访问log_transaction相关的数据结构的方法。在整个Apache代码中,ap_hook_get_log_transaction只被引用到了一次——在mod_info中,用于遍历log_transaction的钩子函数数组,进行查找。

5.    ap_hook_log_transaction的其他参数
AP_DECLARE(void) ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf,
                                const char *const *aszPre,
                                const char * const *aszSucc, int nOrder)

以上函数原型中,pf为实际的钩子函数的指针,而其他三个参数主要用于钩子的排序(见下一小节),其意义如下:
aszPre        此钩子的前驱节点,也即此钩子必须排在哪个钩子之后
aszSucc     此钩子的后驱节点,也即此钩子必须排在哪个钩子之前
nOrder        此钩子顺序值(也可以视作排序的优先级)

6.    钩子的排序
不同的模块可能对同一钩子挂载多个钩子函数,如何决定这些钩子函数被调用的先后顺序呢。
通过对apr_hooks.c中排序相关的代码分析,钩子函数的排序主要由以下规则决定:
1)    Order——钩子函数排序时,首先会用快速排序法对钩子函数的数组进行一次排序,qsort使用的比较函数是crude_order:
static int crude_order(const void *a_,const void *b_)
{
    const TSortData *a=a_;
    const TSortData *b=b_;

return a->nOrder-b->nOrder;
}
也即Order越小的钩子函数排在越前面。系统定义的Order有这几种:
/** run this hook first, before ANYTHING */
#define APR_HOOK_REALLY_FIRST    (-10)
/** run this hook first */
#define APR_HOOK_FIRST        0
/** run this hook somewhere */
#define APR_HOOK_MIDDLE        10
/** run this hook after every other hook which is defined*/
#define APR_HOOK_LAST        20
/** run this hook last, after EVERYTHING */
#define APR_HOOK_REALLY_LAST    30

2)    前驱和后驱——完成基于Order的排序后,还会根据钩子函数相关的前驱(Predecessors)和后驱(Successors)进行调整。此算法的流程如下:
a)    通过遍历钩子数组,计算每个钩子有多少个前驱(见apr_hooks.c中的prepare函数)
b)    初始化一个链表
c)    根据每个钩子的前驱数量,确定其在链表中的位置(见apr_hooks.c中的tsort函数)
d)    将钩子插入链表
e)    遍历链表,生成一个新的钩子数组

此算法的流程稍显复杂,在Apache中也使用很少。大多数地方都只使用Order来决定钩子的顺序。

此外,APR提供了一个单独的函数apr_hook_sort_all来对系统内所有的Hook进行排序。这带来了一个问题:_hooks是静态函数,那apr_hook_sort_all是怎么获得系统内的所有Hooks呢?

解答就在钩子的挂载函数中——注意ap_hook_log_transaction中的这几句代码:
    if(!_hooks.link_log_transaction)
    {
        _hooks.link_log_transaction=apr_array_make(apr_hook_global_pool,
                                                                                            1,
                                                                                            sizeof(ap_AP_log_transaction_t));
        apr_hook_sort_register(log_transaction,&_hooks.link_log_transaction);
    }

在创建一个新的钩子数组之后,调用了apr_hook_sort_register函数,此函数将新建的钩子数组注册到一个全局表中去。这样apr_hook_sort_all就可以对所有的钩子数组进行排序了。

Apache Hook机制解析(中)——细节讨论相关推荐

  1. Apache Hook机制解析(下)——实战:在自己的代码中使用Apache的钩子

    在前文<Apache Hook机制解析(上)--钩子机制的实现>和<Apache Hook机制解析(中)--细节讨论>的基础上,我们对Apache的钩子机制已经有了较多的了解, ...

  2. Apache Hook机制解析(上)——钩子机制的实现

    Apache中大量使用了Hook机制,使得第三方开发Module可以扩展Apache服务器的默认处理. Apache Hook功能可以简述如下: 1.    程序主框架根据名称声明和定义Hook 2. ...

  3. memcached学习笔记6--浅谈memcached的机制 以及 memcached细节讨论

    附:请浅谈memcached的机制 答: ①基于C/S架构,协议比较简单 c/s架构,此时memcached为服务器端,我们可以使用如PHP,c++/c等程序连接memcached服务器. memca ...

  4. Apache运行机制剖析

    Apache运行机制剖析: 1. B/S交互过程 浏览器(Browser)和服务器(Web Server)的交互过程: 1.  浏览器向服务器发出HTTP请求(Request). 2.  服务器收到浏 ...

  5. Android插件化原理解析——Hook机制之Binder Hook

    Android系统通过Binder机制给应用程序提供了一系列的系统服务,诸如ActivityManagerService,ClipboardManager, AudioManager等:这些广泛存在系 ...

  6. Android插件化原理解析——Hook机制之动态代理

    使用代理机制进行API Hook进而达到方法增强是框架的常用手段,比如J2EE框架Spring通过动态代理优雅地实现了AOP编程,极大地提升了Web开发效率:同样,插件框架也广泛使用了代理机制来增强系 ...

  7. Android 插件化原理解析——Hook机制之AMSPMS

    在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是代理方式和Binder Hook:插件框架通过AOP实现了插件使用和开发的透明性.在讲述DroidPlugin如何实现四大组件的插件 ...

  8. android handler的机制和原理_Android 插件化原理——Hook机制之AMSamp;PMS解析

    在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是代理方式和Binder Hook:插件框架通过AOP实现了插件使用和开发的透明性.在讲述DroidPlugin如何实现四大组件的插件 ...

  9. Windows中的Hook机制

    引入 Hook,被译作"钩子"或者"挂钩". 我在另一篇博客中也简单提出这种机制vue2的生命周期函数 vue框架中的生命周期函数就是一种钩子函数,它是一种中断 ...

最新文章

  1. python怎么导入文件-Python模块导入详解
  2. python绘制简单图形-python绘制数学图形(堪比matlab)
  3. 模糊数学笔记:四、模糊矩阵与模糊关系
  4. 使用MAT(Memory Analyzer Tool)工具分析dump文件--转
  5. ccf-csp #201709-2 公共钥匙盒
  6. 对Spring创建对象的思考
  7. 线程的状态和基本操作
  8. Codeforces 576D. Flights for Regular Customers(倍增floyd+bitset)
  9. 随机森林、gbdt算法
  10. 作业二在校大学生零食消费调查问卷
  11. chrome中Js的setAttribute支持不好?
  12. 一级 计算机应用基础,一级计算机应用基础(教材浓缩精华版)
  13. 图形变换之旋转变换公式推导
  14. (详解)----冒泡排序---(图解)
  15. android wp模拟器,玩家必看,WP8 ROM模拟器游戏图文教程
  16. Criteo使用Cassandra存储后端实现Graphite的规模化
  17. docker: 打包h5项目的镜像
  18. 2022.6.2 质数(素数)与合数
  19. 论文阅读:FFA-Net: Feature Fusion Attention Network for Single Image Dehazing
  20. scala和java类_Scala(和Java)中的类和类型有什么区别?

热门文章

  1. 编程软件python中的if用法-适合Python初学者的一些编程技巧
  2. 关于python中程序流程结构-Python程序结构
  3. python语言特点有哪些-python语言的有何特点?
  4. python使用教程cmd啥意思-python中执行cmd的方式
  5. python怎么导入txt文件夹-python读取一个目录下所有txt里面的内容方法
  6. python应该怎么自学-我是一个毫无基础的菜鸟,想自学Python,该怎么入手?
  7. python3-Python3 zip() 函数
  8. python爬虫教程视频-13天搞定Python分布爬虫
  9. CondaHTTPError: HTTP 404 NOT FOUND for url https://pypi.tuna.tsinghua.edu.cn/simple/ 错误
  10. 鸿蒙系统的功能如何,华为鸿蒙系统发布会,这个功能怎么那么像小米MIUI的