Apache Hook机制解析(中)——细节讨论
本文在上文《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机制解析(中)——细节讨论相关推荐
- Apache Hook机制解析(下)——实战:在自己的代码中使用Apache的钩子
在前文<Apache Hook机制解析(上)--钩子机制的实现>和<Apache Hook机制解析(中)--细节讨论>的基础上,我们对Apache的钩子机制已经有了较多的了解, ...
- Apache Hook机制解析(上)——钩子机制的实现
Apache中大量使用了Hook机制,使得第三方开发Module可以扩展Apache服务器的默认处理. Apache Hook功能可以简述如下: 1. 程序主框架根据名称声明和定义Hook 2. ...
- memcached学习笔记6--浅谈memcached的机制 以及 memcached细节讨论
附:请浅谈memcached的机制 答: ①基于C/S架构,协议比较简单 c/s架构,此时memcached为服务器端,我们可以使用如PHP,c++/c等程序连接memcached服务器. memca ...
- Apache运行机制剖析
Apache运行机制剖析: 1. B/S交互过程 浏览器(Browser)和服务器(Web Server)的交互过程: 1. 浏览器向服务器发出HTTP请求(Request). 2. 服务器收到浏 ...
- Android插件化原理解析——Hook机制之Binder Hook
Android系统通过Binder机制给应用程序提供了一系列的系统服务,诸如ActivityManagerService,ClipboardManager, AudioManager等:这些广泛存在系 ...
- Android插件化原理解析——Hook机制之动态代理
使用代理机制进行API Hook进而达到方法增强是框架的常用手段,比如J2EE框架Spring通过动态代理优雅地实现了AOP编程,极大地提升了Web开发效率:同样,插件框架也广泛使用了代理机制来增强系 ...
- Android 插件化原理解析——Hook机制之AMSPMS
在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是代理方式和Binder Hook:插件框架通过AOP实现了插件使用和开发的透明性.在讲述DroidPlugin如何实现四大组件的插件 ...
- android handler的机制和原理_Android 插件化原理——Hook机制之AMSamp;PMS解析
在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是代理方式和Binder Hook:插件框架通过AOP实现了插件使用和开发的透明性.在讲述DroidPlugin如何实现四大组件的插件 ...
- Windows中的Hook机制
引入 Hook,被译作"钩子"或者"挂钩". 我在另一篇博客中也简单提出这种机制vue2的生命周期函数 vue框架中的生命周期函数就是一种钩子函数,它是一种中断 ...
最新文章
- python怎么导入文件-Python模块导入详解
- python绘制简单图形-python绘制数学图形(堪比matlab)
- 模糊数学笔记:四、模糊矩阵与模糊关系
- 使用MAT(Memory Analyzer Tool)工具分析dump文件--转
- ccf-csp #201709-2 公共钥匙盒
- 对Spring创建对象的思考
- 线程的状态和基本操作
- Codeforces 576D. Flights for Regular Customers(倍增floyd+bitset)
- 随机森林、gbdt算法
- 作业二在校大学生零食消费调查问卷
- chrome中Js的setAttribute支持不好?
- 一级 计算机应用基础,一级计算机应用基础(教材浓缩精华版)
- 图形变换之旋转变换公式推导
- (详解)----冒泡排序---(图解)
- android wp模拟器,玩家必看,WP8 ROM模拟器游戏图文教程
- Criteo使用Cassandra存储后端实现Graphite的规模化
- docker: 打包h5项目的镜像
- 2022.6.2 质数(素数)与合数
- 论文阅读:FFA-Net: Feature Fusion Attention Network for Single Image Dehazing
- scala和java类_Scala(和Java)中的类和类型有什么区别?
热门文章
- 编程软件python中的if用法-适合Python初学者的一些编程技巧
- 关于python中程序流程结构-Python程序结构
- python语言特点有哪些-python语言的有何特点?
- python使用教程cmd啥意思-python中执行cmd的方式
- python怎么导入txt文件夹-python读取一个目录下所有txt里面的内容方法
- python应该怎么自学-我是一个毫无基础的菜鸟,想自学Python,该怎么入手?
- python3-Python3 zip() 函数
- python爬虫教程视频-13天搞定Python分布爬虫
- CondaHTTPError: HTTP 404 NOT FOUND for url https://pypi.tuna.tsinghua.edu.cn/simple/ 错误
- 鸿蒙系统的功能如何,华为鸿蒙系统发布会,这个功能怎么那么像小米MIUI的