一、簡介 為了讓第三方開發的Module可以擴展伺服器的默認處理,Apache使用了Hook機制。本文在源碼基礎上對Hook實現原理和結構進行分析,結合http://blog.csdn.net/ConeZXY/archive/2007/11/22/1898000.aspx和http://www.loveopensource.com/?p=18兩篇文章將會更容易理解Hook機制實現原理。 Apache啟動和運行被分成許多階段,如果某些階段允許第三方開發的module進行擴展,在此階段便會實現一些Hook,通過該Hook便可以掛載用戶自定義的Module。計算機程序是數據結構和演算法的結合體,Hook核心數據結構是一個array,每一個array項存儲一個要執行的函數指針,而hook演算法由三個函數來實現:hook, run和hook_get(註:這三個名稱是對hook函數的簡稱,在下文將看到,不同hook對應的函數名不相同)。假設我們要實現一個名為example的hook,以下內容將以example為例來探索hook原理。 二、Hook array結構分析 每一個Hook需要一個array存儲要執行的函數指針,apache中,每個hook都會定義一個變數:_hooks,以example hook為例,以下是該變數的定義: static struct {apr_array_header_t * link_example} _hooks; 其中apr_array_header_t 是apache的apr中定義的一個array管理結構,其定義如下: struct apr_array_header_t { /** The pool the array is allocated out of */ apr_pool_t *pool; /** The amount of memory allocated for each element of the array */ int elt_size; /** The number of active elements in the array */ int nelts; /** The number of elements allocated in the array */ int nalloc; /** The elements in the array */ char *elts; }; apr_array_header_t 結構實現array結構並對其進行管理,array的每一項稱為element,其中pool記錄該array是由哪個pool分配的空間,elt_size記錄每一個element的size,nelts表示array中有效的element數,nalloc表示系統已經給該array分配的element數,elts指針指向array的第一個element地址。Apache採用比較靈活的方法管理array,在我們向array中添加一個element時,它會判斷array中是否有空閑的位置(即array中已經分配的element數大於有效的element數,nalloc>nelts),如果沒有空閑位置(即nelts == nalloc),則array會重新申請大小為:2 * nalloc的空間。 Hook array的每個element如何存儲函數指針,這涉及到hook定義的另外一個LINK數據結構,同樣假設我們要定義的Hook名字為:example,則對應的LINK結構定義如下: typedef struct ap_LINK_example_t { ap_HOOK_example * pFunc; const char* const aszPredecessor; const char* const aszSuccessors; int nOrder; }ap_LINK_example; 定義中的pFunc就是要執行的函數指針,Hook array中每一個element都是ap_LINK_example結構,apr_array_header_t 結構中的elt_size將會等於sizeof(ap_LINK_example),而elts指向第一個ap_LINK_example地址。 通過以上對Hook array的分析,我們便可以畫出Hook array的結構圖: