leevis.com icon indicating copy to clipboard operation
leevis.com copied to clipboard

apache httpd 代码分析

Open vislee opened this issue 7 years ago • 0 comments

概述

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

vislee avatar May 02 '18 12:05 vislee