在 Post Read Configuration 中使用 ap_retained_data_create/get 开发

Developing Cross Platform Apache Modules using ap_retained_data_create/get in Post Read Config

本文关键字:data retained create 开发 get ap Read Post Configuration      更新时间:2023-10-16

在构建跨平台模块时,我非常高兴地在 Apache 2.4 的设计中调试了几个小时。

我面临的问题是 Apache 在启动时加载配置文件两次,从而加载模块本身两次。一旦我猜到测试配置并读取命令结构,然后下一步填写服务器运行的空白。这通常不会有任何问题,但我需要在为任何客户端提供服务之前在加载时加载模块的配置,并且只解析我的模块需求一次且仅一次。

由于我使用了许多资源,包括数据库等,因此我认为多次运行不是最好的主意,尤其是在数据库服务器上受到攻击时。

在线手册("开发人员 API 2.5")说,不要使用旧方法,我将让读者查找,而是使用ap_retained_data_get和ap_retained_data_create在模块卸载时保留数据。最好将标志传递到已通过测试阶段的下一阶段。

这就是头痛所在。这不是它在Windows上的工作方式。

Linux 确实以两次方式运行,但 Windows 以四次运行。

在配置后读取钩子中使用此方法适用于 Linux,但不适用于 Windows

    // variables for base config start
    const char  *flag = "some_prefixed_flag_to_mashup_with_other_flags";
    void        *init_flag = NULL;
    int         dbl = APLOG_TRACE4;
    // logger
    logging logger(NULL, s, p);     
    // determine if this is the first time we have loaded
    init_flag = ap_retained_data_get(flag);
    // check flag result
    if (init_flag == NULL) 
    {
        // breakpoint
        stdLog(logger, INFX_LOG_DATA, dbl);
        // set first time flag local
        ap_retained_data_create(flag, 1);
    }
    // call initization routine
    else
    {
        // do something here
    }

请注意,我在模块中导出C++代码,因此使用类。此外,为简洁起见,缺少一些变量声明。

所以这对Windows来说应该足够了吧?错。我必须反向学习,因为我首先在Windows上构建,但是Windows有四次而不是两次。那里的初始化仍将运行两次。

我的下一个解决方案如下:

    // variables for base config start
    const char  *flag = "some_prefixed_flag_to_mashup_with_other_flags";
    void        *init_flag = NULL;
    char        *pidname;
    int         dbl = APLOG_TRACE4;
    pid_t       pidNKey;
    apr_file_t  *pidfile;       
    // logger
    logging logger(NULL, s, p);     
    // determine if this is the first time we have loaded
    init_flag = ap_retained_data_get(flag);
    // check flag result
    if (init_flag == NULL) 
    {
        // breakpoint
        stdLog(logger, INFX_LOG_DATA, dbl);
        // set first time flag local
        ap_retained_data_create(flag, 1);
    }
    else
    {
        // break point
        stdLog(logger, INFX_LOG_DATA, dbl);
        // create a pid if not exists
        if (ap_read_pid(p, "logs/httpd.pid", &pidNKey) == OK)
        {
            // break point
            stdLog(logger, INFX_LOG_DATA, dbl);
            // create a pid especially for our setup
            pidname = apr_psprintf(ptemp, "logs/infx.%d.pid", pidNKey);
            // if pidfile does not exist then create it
            if (!fileExists(pidname, ptemp))
            {
                // break point
                stdLog(logger, INFX_LOG_DATA, dbl);
                // create the pid
                apr_file_open(&pidfile, pidname, APR_WRITE|APR_APPEND|APR_CREATE, INFX_BASE_PERM, ptemp);
                // add nonsensical data to it
                apr_file_puts("1", pidfile);
                // cllose the file and wait for run 2
                apr_file_close(pidfile);
            }
            // begin work
            else 
            {
                // break point
                stdLog(logger, INFX_LOG_DATA, dbl);
                // we no longer require the pid file
                apr_file_remove(pidname, ptemp);
            }
        }
    }

似乎有效....好的,我完成了这一部分,对吧?错!我去了Linux盒子和隔离区间城市。我敢肯定,许多经验丰富的Apache开发人员现在可能会摇头,但这些人并没有记录这些问题。

我的最终解决方法是将 Windows 代码包装在定义块中。我不确定是否有更好的方法,但它对我有用。因此,以下内容在两个平台上都有效,没有段错误。

    // variables for base config start
    const char  *flag = "some_prefixed_flag_to_mashup_with_other_flags";
    void        *init_flag = NULL;
    int         dbl = APLOG_TRACE4;
    // logger
    logging logger(NULL, s, p);     
    // determine if this is the first time we have loaded
    init_flag = ap_retained_data_get(flag);
    // check flag result
    if (init_flag == NULL) 
    {
        // breakpoint
        stdLog(logger, INFX_LOG_DATA, dbl);
        // set first time flag local
        ap_retained_data_create(flag, 1);
    }
    // call initization routine
    else
    {
        // break point
        stdLog(logger, INFX_LOG_DATA, dbl);
        #if defined(WIN32)
        // create a pid if not exists
        if (ap_read_pid(p, "logs/httpd.pid", &pidNKey) == OK)
        {
            // break point
            stdLog(logger, INFX_LOG_DATA, dbl);
            // create a pid especially for our setup
            pidname = apr_psprintf(ptemp, "logs/infx.%d.pid", pidNKey);
            // if pidfile does not exist then create it
            if (!fileExists(pidname, ptemp))
            {
                // break point
                stdLog(logger, INFX_LOG_DATA, dbl);
                // create the pid
                apr_file_open(&pidfile, pidname, APR_WRITE|APR_APPEND|APR_CREATE, INFX_BASE_PERM, ptemp);
                // add nonsensical data to it
                apr_file_puts("1", pidfile);
                // cllose the file and wait for run 2
                apr_file_close(pidfile);
            }
            // begin work
            else 
            {
                // break point
                stdLog(logger, INFX_LOG_DATA, dbl);
                // we no longer require the pid file
                apr_file_remove(pidname, ptemp);
        #endif
                // do something here for both platforms
        #if defined(WIN32)
            }
        }
        // crash if we do get a proper pid
        else
        {
            // breakpoint
            stdLog(logger, INFX_LOG_DATA, APLOG_CRIT, "HTTPD File not found? A Bug?");
            // set status
            return HTTP_INTERNAL_SERVER_ERROR;
        }
        #endif
    }           

希望其他人可以从中受益。