国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Apache中的掛鉤剖析(3)

2019-11-17 04:50:12
字體:
供稿:網(wǎng)友
5.5.7 可選掛鉤
與標(biāo)準(zhǔn)掛鉤相比,可選掛鉤基本上沒有太大的差異,唯一的區(qū)別就在于可選掛鉤不一定需要被實(shí)現(xiàn)——這看起來令人迷惑的。不過你很快就會(huì)明白了。考慮一下,假如某個(gè)掛鉤Hook_A是聲明在一個(gè)可選模塊中,那么正常情況下該模塊沒有被加載。如此此時(shí)某個(gè)模塊想使用掛鉤Hook_A,那么會(huì)發(fā)生什么情況呢。對(duì)于標(biāo)準(zhǔn)模塊,Apache可能根本就無法進(jìn)行編譯。而可選掛鉤則可以解決這種問題。對(duì)于可選掛鉤,即使它沒有被導(dǎo)入并運(yùn)行,其余的模塊也可以使用它。
可選掛鉤的聲明方法與標(biāo)準(zhǔn)掛鉤聲明沒有任何區(qū)別,都是通過AP_DECLARE_HOOK進(jìn)行的,比如下面的語句聲明一個(gè)可選掛鉤:
AP_DECLARE_HOOK(int , optional_hook , (request_rec *r , int n))
與標(biāo)準(zhǔn)掛鉤相比,可選掛鉤沒有內(nèi)部私有的數(shù)據(jù)結(jié)構(gòu)。在標(biāo)準(zhǔn)掛鉤中,為了保存各個(gè)模塊對(duì)聲明的掛鉤的使用情況,通過聲明AP_HOOK_STRUCT結(jié)構(gòu)來實(shí)現(xiàn)。這種做法實(shí)際上是由掛鉤實(shí)現(xiàn)者自行進(jìn)行維護(hù);而對(duì)于可選掛鉤,模塊編寫者可以不需要維護(hù)該AP_HOOK_STRUCT結(jié)構(gòu)了,該結(jié)構(gòu)則轉(zhuǎn)交內(nèi)核維護(hù)。
在實(shí)現(xiàn)上,可選掛鉤的聲明從標(biāo)準(zhǔn)掛鉤的AP_IMPLEMENT_HOOK_RUN_ALL形式轉(zhuǎn)變?yōu)锳P_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL
5.5.7.1可選掛鉤數(shù)組
在Apache2.0中,任何模塊對(duì)可選掛鉤的調(diào)用信息都由Apache核心進(jìn)行維護(hù)。在Apache內(nèi)部,核心定義了兩個(gè)全局哈希表s_phOptionalHooks和s_phOptionalFunctions分別保存所有的可選掛鉤以及對(duì)應(yīng)的掛鉤處理句柄。S_phOptionalHooks哈希表中,可選掛鉤名稱用來作為哈希表Key鍵,而掛鉤對(duì)應(yīng)的掛鉤數(shù)組則作為哈希表的Value值。其結(jié)構(gòu)如上圖所示。在APR_hooks.c中,Apache提供了兩個(gè)支持函數(shù):apr_optional_hook_get和apr_optional_hook_add。
Apache中的掛鉤剖析(3)(圖一)
apr_optional_hook_get函數(shù)用來在哈希表s_phOptionalHooks中查找指定掛鉤的掛鉤數(shù)組,假如找到了則返回?cái)?shù)組;否則返回NULL。
apr_optional_hook_add函數(shù)的原型聲明如下:
APU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
                    const char * const *aszPre,
                    const char * const *aszSucc,int nOrder)
該函數(shù)主要在可選掛鉤szName數(shù)組中,增加一個(gè)登記項(xiàng),登記的掛鉤函數(shù)為pfn。同時(shí)aszPre、aszSucc以及nOrder與標(biāo)準(zhǔn)掛鉤的含義相同。
在登記之前,函數(shù)必須能夠在哈希表中找到掛鉤szName對(duì)應(yīng)的掛鉤數(shù)組,這個(gè)可以通過apr_optional_hook_get來完成。由于可選掛鉤可以沒有任何掛鉤函數(shù),因此上圖中掛鉤數(shù)組為NULL也是可能的,此時(shí)必須為該掛鉤首先生成掛鉤數(shù)組,將該掛鉤數(shù)組在哈希表中與鍵szName關(guān)聯(lián)起來,同時(shí)進(jìn)行排序。
假如szName掛鉤數(shù)組已經(jīng)存在,則直接調(diào)用apr_array_push相關(guān)信息壓入數(shù)組并賦值。
可選掛鉤數(shù)組中每個(gè)元素的結(jié)構(gòu)都是apr_LINK__optional_t類型,其是宏APR_DECLARE_EXTERNAL_HOOK展開的結(jié)果,apr_LINK__optional_t結(jié)構(gòu)實(shí)際如下所示:
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)
對(duì)于標(biāo)準(zhǔn)掛鉤,注冊(cè)使用掛鉤通常使用ap_hook_name之類的函數(shù),這些函數(shù)最終將使用信息登記到掛鉤數(shù)組中去。而對(duì)于可選掛鉤,由于不存在AP_HOOK_STRUCT宏,因此也就不存在掛鉤數(shù)組了。在前面我們提到過,可選掛鉤的保存是由Apache內(nèi)核維護(hù)的,我們展開宏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
對(duì)于標(biāo)準(zhǔn)掛鉤,其實(shí)現(xiàn)分為VOID、FIRST和ALL三種,而對(duì)于可選掛鉤,實(shí)現(xiàn)則歸結(jié)只有一種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就是一個(gè)可選掛鉤,該掛鉤實(shí)現(xiàn)如下:
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook,
                                    (request_rec *r, int flags),
                                    (r, flags),
                                    OK, DECLINED)
     該宏展開后即實(shí)現(xiàn)了ap_run_status_hook函數(shù),其實(shí)現(xiàn)過程,即展開結(jié)果如下所示:
     AP_DECLARE(int) ap_run_status_hook(request_rec* r,int flags)
     {
         ap_LINK_status_hook_t *pHook;
         int n;
         int rv;
    apr_array_header_t *pHookArray=apr_optional_hook_get(status_name);
    if(!pHookArray)
return ok;
    pHook=(ap_LINK_status_hook_t *)pHookArray->elts;
    for(n=0 ; n < pHookArray->nelts ; ++n)
{
rv=(pHook[n].pFunc)(r,flags);
if(rv != ok && rv != decline)
    return rv;
}
    return ok;
     }

5.5.8 可選函數(shù)
與掛鉤存在類似的問題,函數(shù)也可能存在可選掛鉤的問題。假如Apache在調(diào)用某一個(gè)函數(shù)的時(shí)候,該函數(shù)尚未被加載,會(huì)發(fā)生什么呢。你可能覺得DSO是個(gè)好的解決方法。假如指定的函數(shù)沒有,則動(dòng)態(tài)加載DSO模塊進(jìn)行查找。不過這種策略并不但是最完美的方案。首先,不是所有的平臺(tái)都支持DSO;另一方面,
可選函數(shù)的特點(diǎn)正如其名,這就決定了它相對(duì)于Apache的動(dòng)態(tài)性。正常的函數(shù)都是編寫之后才會(huì)加入Apache中進(jìn)行編譯,而且一旦編譯就無法更改。而可選函數(shù)則是在需要的時(shí)候動(dòng)態(tài)產(chǎn)生的。在產(chǎn)生之前,沒有人為之進(jìn)行過專門的編寫,因此鏈接代碼中自然也就找不到該函數(shù)的實(shí)現(xiàn)。
可選函數(shù)的使用可以分為五大步驟:聲明、實(shí)現(xiàn)、注冊(cè)、獲取以及函數(shù)調(diào)用。
5.5.8.1.可選函數(shù)的聲明
聲明一個(gè)可選函數(shù)通過宏APR_DECLARE_OPTIONAL_FN來實(shí)現(xiàn),比如我們假如想聲明一個(gè)optional_fun可選函數(shù),其返回int類型,參數(shù)需要字符串類型,那么聲明可以如下:
APR_DECLARE_OPTIONAL_FN(int,optional_fun,(const char* params))
APR_DECLARE_OPTIONAL_FN宏定義如下:
 #define APR_DECLARE_OPTIONAL_FN(ret,name,args) /
typedef ret (APR_OPTIONAL_FN_TYPE(name)) args
假如將上面的宏展開,則可以看出,該宏只是聲明了一個(gè)apr_OFN_optional_fun_t類型的函數(shù)指針:
typedef int (apr_OFN_optional_fun_t)(const char* params)
一旦聲明完畢,我們則將其進(jìn)行實(shí)現(xiàn)如下,在實(shí)現(xiàn)中必須注重名稱以及函數(shù)參數(shù)類型的匹配:
int optional_fun(const char* params)
{
       &hellip;…
       return 0;
}
5.5.8.2.可選函數(shù)的注冊(cè)
可選函數(shù)由Apache核心統(tǒng)一維護(hù)。與可選掛鉤類似,Apache核心維護(hù)了一個(gè)全局的哈希表s_phOptionalFunctions,該哈希表的鍵為可選函數(shù)的名稱,而值則是對(duì)應(yīng)的函數(shù)指針。為了便于Apache使用,我們必須在s_phOptionalFunctions中登記可選函數(shù)。函數(shù)的注冊(cè)通過APR_REGISTER_OPTIONAL_FN進(jìn)行,APR_REGISTER_OPTIONAL_FN定義如下:
#define APR_REGISTER_OPTIONAL_FN(name) do { /
 APR_OPTIONAL_FN_TYPE(name) *apu__opt = name; /
 apr_dynamic_fn_register(#name,(apr_opt_fn_t *)apu__opt); /
} while(0)
該宏內(nèi)部實(shí)際調(diào)用了函數(shù)apr_dynamic_fn_register進(jìn)行實(shí)際的注冊(cè)。事實(shí)上,Apache中提供了相關(guān)函數(shù)來支持對(duì)s_phOptionalFunctions的操作,除了apr_dynamic_fn_register之外,還包括apr_register_optional_fn、apr_dynamic_fn_retrieve、apr_retrieve_optional_fn。不過其中apr_retrieve_optional_fn和apr_register_optional_fn在Apache2.0中已經(jīng)被廢棄,因此不再多說。
apr_dynamic_fn_register的原型如下:
APU_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName,
                                                  apr_opt_fn_t *pfn)

參數(shù)szName是可選函數(shù)的名稱,pfn則是實(shí)際可選函數(shù)的指針。假如s_phOptionalFunctions哈希表存在,函數(shù)只是簡(jiǎn)單的調(diào)用apr_hash_set將記錄插入表中。
apr_dynamic_fn_retrieve函數(shù)原型為
APU_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName)
該函數(shù)根據(jù)給定的函數(shù)名稱獲取實(shí)際的函數(shù)指針。
事實(shí)上,這兩個(gè)函數(shù)都不答應(yīng)直接調(diào)用,它們作為Apache的內(nèi)部函數(shù)而存在,對(duì)外提供的則是宏APR_REGISTER_OPTIONAL_FN和APR_RETRIEVE_OPTIONAL_FN。
對(duì)于optional_fun可選函數(shù),注冊(cè)語句如下:
APR_REGISTER_OPTIONAL_FN(optional_fun);
當(dāng)用戶想使用可選函數(shù)的時(shí)候,首先必須獲得其函數(shù)指針,用法如下:
APR_OPTIONAL_FN_TYPE(some_fn) *pfn;
pfn=APR_RETRIEVE_OPTIONAL_FN(some_fn);
 
 
5.5.8.3.可選函數(shù)的使用
 
5.5.9智能掛鉤
5.5.10掛鉤工作機(jī)制
在前面的部分,我們對(duì)掛鉤進(jìn)行了具體的分析,但是還缺乏一個(gè)整體上的概念。從整體上來看掛鉤的工作機(jī)制可以用下圖來描述:
Apache中的掛鉤剖析(3)(圖二)
一個(gè)模塊從掛鉤的角度來看,其最重要的無非是兩個(gè)方面:掛鉤注冊(cè)函數(shù)和掛鉤處理函數(shù)。掛鉤注冊(cè)函數(shù)通常是模塊結(jié)構(gòu)中的register_hooks函數(shù)指針,該函數(shù)指針將調(diào)用實(shí)際的掛鉤注冊(cè)函數(shù)進(jìn)行掛鉤注冊(cè)。掛鉤注冊(cè)的過程很簡(jiǎn)單,通過宏ap_hook_xxx實(shí)現(xiàn)。比如上圖中聲明了兩個(gè)掛鉤abc和xyz。
與此同時(shí),模塊中也將聲明與掛鉤對(duì)應(yīng)的掛鉤函數(shù),該掛鉤被觸發(fā)的時(shí)候,該函數(shù)將被調(diào)用。正如前面描述,可以使用宏ap_run_xxx觸發(fā)指定的掛鉤。不過掛鉤的觸發(fā)通常是由核心模塊在對(duì)客戶端請(qǐng)求進(jìn)行處理的過程中進(jìn)行。
我們來看一個(gè)具體的例子,這是核心模塊中關(guān)于掛鉤的部分。
從模塊的結(jié)構(gòu)中可以看出,模塊結(jié)構(gòu)中包含一個(gè)指針register_hook,該指針通常指向模塊中的實(shí)際的掛鉤注冊(cè)函數(shù),比如,對(duì)于核心模塊而言,其掛鉤注冊(cè)函數(shù)register_hooks,那么結(jié)構(gòu)中的該指針也為register_hooks:
AP_DECLARE_DATA module core_module = {
    STANDARD20_MODULE_STUFF,
    create_core_dir_config,       /* create per-Directory config structure */
    merge_core_dir_configs,       /* merge per-directory config structures */
    create_core_server_config,    /* create per-server config structure */
    merge_core_server_configs,    /* merge per-server config structures */
    core_cmds,                    /* command apr_table_t */
    register_hooks                /* register hooks */

};
而具體的register_hooks函數(shù)則如下:
static void register_hooks(apr_pool_t *p)
{
    ap_hook_create_connection(core_create_conn, NULL, NULL,
                              APR_HOOK_REALLY_LAST);
    ap_hook_pre_connection(core_pre_connection, NULL, NULL,
                           APR_HOOK_REALLY_LAST);
 
    ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_access_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
    APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
                      APR_HOOK_MIDDLE);
    ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
……
}
該函數(shù)的任務(wù)非常的簡(jiǎn)單,即聲明該模塊需要實(shí)現(xiàn)的掛鉤,以及對(duì)應(yīng)的處理函數(shù),供主程序調(diào)用。

關(guān)于作者
張中慶,目前主要的研究方向是嵌入式瀏覽器,移動(dòng)中間件以及大規(guī)模服務(wù)器設(shè)計(jì)。目前正在進(jìn)行Apache的源代碼分析,計(jì)劃出版《Apache源代碼全景分析》上下冊(cè)。Apache系列文章為本書的草案部分,對(duì)Apache感愛好的朋友可以通過flydish1234 at sina.com.cn與之聯(lián)系!

假如你覺得本文不錯(cuò),請(qǐng)點(diǎn)擊文后的“推薦本文”鏈接!!


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 香格里拉县| 永顺县| 镇江市| 长汀县| 湛江市| 南靖县| 蓬溪县| 郸城县| 兴仁县| 齐齐哈尔市| 边坝县| 南安市| 新野县| 游戏| 胶州市| 星子县| 昆山市| 洪湖市| 贵德县| 榕江县| 梁山县| 高尔夫| 平罗县| 常德市| 甘洛县| 郧西县| 台北县| 江津市| 资溪县| 抚宁县| 阿拉尔市| 曲周县| 两当县| 呈贡县| 东宁县| 安岳县| 宝丰县| 西城区| 铜川市| 云安县| 襄城县|