leevis.com
leevis.com copied to clipboard
apache httpd 代码分析
概述
httpd 作为全球部署量最多的web 服务器。 代码模块化使得有大量的第三方功能模块。然而有时候我们自己也需要了解一下httpd的运行机制。了解下httpd的模块开发。
代码分析
代码编译脚本
一些宏定义
- hook函数的定义
// apr_tables.h
/** @see apr_array_header_t */
typedef struct apr_array_header_t apr_array_header_t;
/** An opaque array type */
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_hooks.h
/** macro to declare the hook correctly */
#define APR_DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args) \
typedef ret ns##_HOOK_##name##_t args; \
link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \
const char * const *aszPre, \
const char * const *aszSucc, int nOrder); \
link##_DECLARE(ret) ns##_run_##name args; \
APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name); \
typedef struct ns##_LINK_##name##_t \
{ \
ns##_HOOK_##name##_t *pFunc; \
const char *szName; \
const char * const *aszPredecessors; \
const char * const *aszSuccessors; \
int nOrder; \
} ns##_LINK_##name##_t;
#define APR_HOOK_STRUCT(members) \
static struct { members } _hooks;
#define APR_HOOK_LINK(name) \
apr_array_header_t *link_##name;
// ap_config.h
/**
* Declare a hook function
* @param ret The return type of the hook
* @param name The hook's name (as a literal)
* @param args The arguments the hook function takes, in brackets.
*/
#define AP_DECLARE_HOOK(ret,name,args) \
APR_DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
AP_DECLARE_HOOK(void,child_init,(apr_pool_t *pchild, server_rec *s))
等价于:
typedef void ap_HOOK_child_init_t (apr_pool_t *pchild, server_rec *s); \
AP_DECLARE(void) ap_hook_child_init(ap_HOOK_child_init_t *pf, \
const char * const *aszPre, \
const char * const *aszSucc, int nOrder); \
AP_DECLARE(void) ap_run_child_init (apr_pool_t *pchild, server_rec *s); \
APR_IMPLEMENT_HOOK_GET_PROTO(void,AP,child_init); \
typedef struct ap_LINK_child_init_t \
{ \
ap_HOOK_child_init_t *pFunc; \
const char *szName; \
const char * const *aszPredecessors; \
const char * const *aszSuccessors; \
int nOrder; \
} ap_LINK_child_init_t;
// request.c
APR_HOOK_STRUCT(
APR_HOOK_LINK(translate_name)
APR_HOOK_LINK(map_to_storage)
APR_HOOK_LINK(check_user_id)
APR_HOOK_LINK(fixups)
APR_HOOK_LINK(type_checker)
APR_HOOK_LINK(access_checker)
APR_HOOK_LINK(auth_checker)
APR_HOOK_LINK(insert_filter)
APR_HOOK_LINK(create_request)
)
所以,上述request.c文件中其实是定义了一个结构体:
static struct {
apr_array_header_t *link_translate_name;
apr_array_header_t *link_map_to_storage;
apr_array_header_t *link_check_user_id;
apr_array_header_t *link_fixups;
apr_array_header_t *link_type_checker;
apr_array_header_t *link_access_checker;
apr_array_header_t *link_auth_checker;
apr_array_header_t *link_insert_filter;
apr_array_header_t *link_create_request;
} _hooks;
- hook 函数的实现
// include/ap_config.h
/**
* Implement an Apache core hook that has no return code, and
* therefore runs all of the registered functions. The implementation
* is called ap_run_<i>name</i>.
*
* @param name The name of the hook
* @param args_decl The declaration of the arguments for the hook, for example
* "(int x,void *y)"
* @param args_use The arguments for the hook as used in a call, for example
* "(x,y)"
* @note If IMPLEMENTing a hook that is not linked into the Apache core,
* (e.g. within a dso) see APR_IMPLEMENT_EXTERNAL_HOOK_VOID.
*/
#define AP_IMPLEMENT_HOOK_VOID(name,args_decl,args_use) \
APR_IMPLEMENT_EXTERNAL_HOOK_VOID(ap,AP,name,args_decl,args_use)
// apr_hooks.h
/**
* Implement a hook that has no return code, and therefore runs all of the
* registered functions
* @param ns The namespace prefix of the hook functions
* @param link The linkage declaration prefix of the hook
* @param name The name of the hook
* @param args_decl The declaration of the arguments for the hook
* @param args_use The names for the arguments for the hook
* @note The link prefix FOO corresponds to FOO_DECLARE() macros, which
* provide export linkage from the module that IMPLEMENTs the hook, and
* import linkage from external modules that link to the hook's module.
*/
#define APR_IMPLEMENT_EXTERNAL_HOOK_VOID(ns,link,name,args_decl,args_use) \
APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \
link##_DECLARE(void) ns##_run_##name args_decl \
{ \
ns##_LINK_##name##_t *pHook; \
int n; \
APR_HOOK_INT_DCL_UD; \
\
APR_HOOK_PROBE_ENTRY(ud, ns, name, args_use); \
\
if(_hooks.link_##name) \
{ \
pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \
for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \
{ \
APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName, args_use); \
pHook[n].pFunc args_use; \
APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, 0, args_use); \
} \
} \
\
APR_HOOK_PROBE_RETURN(ud, ns, name, 0, args_use); \
\
}
AP_IMPLEMENT_HOOK_VOID(child_init,
(apr_pool_t *pchild, server_rec *s),
(pchild, s))
#等价于
APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ap,AP,child_init) \
AP_DECLARE(void) ap_run_child_init (apr_pool_t *pchild, server_rec *s) \
{ \
ap_LINK_child_init_t *pHook; \
int n; \
APR_HOOK_INT_DCL_UD; \
\
APR_HOOK_PROBE_ENTRY(ud, ns, child_init, (pchild, s)); \
\
if(_hooks.link_child_init) \
{ \
pHook=(ap_LINK_child_init_t *)_hooks.link_child_init->elts; \
for(n=0 ; n < _hooks.link_child_init->nelts ; ++n) \
{ \
APR_HOOK_PROBE_INVOKE(ud, ns, child_init, (char *)pHook[n].szName, (pchild, s)); \
pHook[n].pFunc (pchild, s); \
APR_HOOK_PROBE_COMPLETE(ud, ns, child_init, (char *)pHook[n].szName, 0, (pchild, s)); \
} \
} \
\
APR_HOOK_PROBE_RETURN(ud, ns, child_init, 0, (pchild, s)); \
\
}
程序入口main函数
- 首先在main.c这个文件中定义了httpd的入口main函数。
- 在main函数中调用init_process初始化进程结构体。
- 初始化一个“pcommands”内存结构体,并在该内存分配三个数组ap_server_pre_read_config、ap_server_post_read_config、ap_server_config_defines。
- 调用ap_setup_prelinked_modules(config.c:665)
- 在main函数首先调用ap_read_config解析配置文件,该函数的定义在config.c文件中。
init_process函数
- 调用apr_app_initialize 初始化全局的内存结构体,然后初始化一个“apr_initialize”的内存结构体。
- 初始化一个“process”内存结构体,并分配一个process_rec结构体(定义在httpd.h:766),该结构体记录了进程启动的一些信息(进程名,参数等)。
ap_setup_prelinked_modules函数
- 初始化ap_preloaded_modules
- 初始化ap_loaded_modules
- 调用apr_hook_sort_all函数
ap_add_module函数
总结
参考: https://blog.csdn.net/zjl410091917/article/details/7289552