Contents

조회 수 8588 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
apache 모듈 만들기 2탄
정리하자.. 2007/06/11 17:22

이제 mod_irdealtest.c 파일을 작성해보자.
먼저 적당한 헤더들을 인클루드 시킨다.
기본적으로 중요한 것들만 일단 넣은다음 에러가 발생하면 하나씩 추가 해보도록 하자.
기본적으로 있어야 할 것들은 다음과 같다.
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"

물론 이것들중 없어도 되는 것이 있을지도 모른다.. 하지만 일단 넘어가자.. 흠흠...
제일먼저 모듈에 대해 선언을 해주어야 한다. 다음과 같이 선언을 해주자.
module AP_MODULE_DECLARE_DATA irdealtest_module;

그리고 아래와 같이 할당 해준다.
할당 해줄때 각각의 인자를 보면 첫번째 인자는 모듈의 버전, 마이너 버전, 모듈의 인덱스, 모듈의 이름, 핸들, 등등의 값을 정해준다.
module AP_MODULE_DECLARE_DATA irdealtest_module =
{
    // Only one callback function is provided.  Real
    // modules will need to declare callback functions for
    // server/directory configuration, configuration merging
    // and other tasks.
    STANDARD20_MODULE_STUFF,
    NULL,
    NULL,

    /*create irdealtest config*/
    create_irdealtest_config,
    NULL,

    /*for config*/
    irdeattest_cmds,

    /* callback for registering hooks */
    mod_irdealtest_register_hooks,
};

첫번째 인자인 STANDAR20_MODULE_STUFF는 다음과 같다.
/** Use this in all standard modules */
#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \
    MODULE_MAGIC_NUMBER_MINOR, \
    -1, \
    __FILE__, \
    NULL, \
    NULL, \
    MODULE_MAGIC_COOKIE, \
    NULL    /* rewrite args spot */

원래 module struct가 매우 여러개의 인자로 되어있는데 그중 일부를 처리해주었다고 보면 되겠다.
더 자세히 보고 싶으면 module struct 정의부분을 살펴보아라.
여튼 첫번째 인자는 그렇고 2,3,4,5 번 인자를 잘살펴봐야 하는데 2,3번째 인자는 Directory/Location 컨테이너 안에서 설정되는 지시어들을 설정해주는 것이고 3,4는 서버에서 설정되는 지시어들을 설정해주는 함수를 등록해주는 것이다.
각각 살펴보면

   2번째      /* create per-directory config structure */
   3번째      /* merge per-directory config structures */
   4번째      /* create per-server config structure */
   5번째      /* merge per-server config structures */

설명에 create라고 되어있는것은 아파치의 첫번째 프로세스가 실행될때 설정하는 것이라고 보면 되고 merge라고 되어있는 것은 두번째 프로세스부터 프로세스가 생성될 때 실행된다고 보면된다.
create와 merge의 두종류의 설정방법을 사용하는 이유는 프로세스들간에 설정값을 동기화하거나 같은 값을 가지게 하려고 사용한다고 보면된다.

6번째 인자는 httpd.conf파일로 부터 읽어드릴는 컨피그 값을 저장 하도록 하는 구조체 이다.
irdealtest_cmds를 살펴보면 
static const command_rec irdealtest_cmds[] =
{
    AP_INIT_TAKE1 ("IrdealMessage",
        add_irdealmessage, NULL, RSRC_CONF, "irdeal's message"),

    AP_INIT_TAKE1 ("IrdealDebug",
        set_debug, NULL, RSRC_CONF, "Set IRDEAL Debug rutine"), {NULL}
};

commane_rec라는 배열로 모듈의 지시어를 저장한다.
여기서 AP_INIT_TAKE1 는 인자를 하나만 받는 지시어를 등록(?)하는 것이다.
AP_INIT_TAKE1이외에도 여러종류의 지시어를 받아들이는 define되어 있다. (http_config.h 참조)
AP_INIT_TAKE1 을 살펴보면,
첫번째 인자는 지시어 이름을 나타낸다. 
두번째 인자는 지시어가 있을때 호출되는 함수를 나타낸다.
보통 지시어로 부터 받은 값을 인자로 가지고 모듈에 필요한 설정을 하는데 사용된다. 
3번째 인자는 두번째 인자에서 등록된 함수로 필요에 의해 넘겨줄 수 있는 값이다.
보통 사용하지 않는듯..
5번째 인자값은 사용법에 관한 메시지, 혹은 디스크립션정도로 생각하자.
4번재 인자값의 의미는 아래와 같은데, 이 지시어가 어디에서 설정될지를 나타낸다.
RSRC_CONF 값은 <Directory>나 <Location> 밖에서 사용되는 것을 알 수 있다. 
/** 
* @defgroup ConfigDirectives Allowed locations for configuration directives.
* The allowed locations for a configuration directive are the union of
* those indicated by each set bit in the req_override mask.
* @{
*/

/**< *.conf is not available anywhere in this override */ 
#define OR_NONE 0

/**< *.conf inside <Directory> or <Location>
  and .htaccess when AllowOverride Limit */
#define OR_LIMIT 1

/**< *.conf anywhere and .htaccess when AllowOverride Options */
#define OR_OPTIONS 2

/**< *.conf anywhere and .htaccess when AllowOverride FileInfo */
#define OR_FILEINFO 4

/**< *.conf inside <Directory> or <Location>
  and .htaccess when AllowOverride AuthConfig */
#define OR_AUTHCFG 8

/**< *.conf anywhere and .htaccess when AllowOverride Indexes */
#define OR_INDEXES 16

/**< unset a directive (in Allow) */
#define OR_UNSET 32

/**< *.conf inside <Directory> or <Location> */
#define ACCESS_CONF 64

/**< *.conf outside <Directory> or <Location> */
#define RSRC_CONF 128

/**< force directive to execute a command 
  which would modify the configuration (like including another 
  file, or IFModule */
#define EXEC_ON_READ 256  

/** this directive can be placed anywhere */
#define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES) 
 
/** @} */

실제 command_struct는 다음과 같다.
struct command_struct {
    /** Name of this command */
    const char *name;
    /** The function to be called when this directive is parsed */
    cmd_func func;
    /** Extra data, for functions which implement multiple commands... */
    void *cmd_data;
    /** What overrides need to be allowed to enable this command. */
    int req_override;
    /** What the command expects as arguments 
     *  @defvar cmd_how args_how*/
    enum cmd_how args_how;
    
    /** 'usage' message, in case of syntax errors */
    const char *errmsg;
};

module AP_MODULE_DECLARE_DATA irdealtest_module 에서 마지막 인자는 mod_irdealtest가 후킹할 함수를 동록하는 함수이다. mod_irdealtest에서는 다음과 같다.
static ap_filter_rec_t *irdealtest_out_filter_handle;

static void mod_irdealtest_register_hooks (apr_pool_t *p)
{   
    irdealtest_out_filter_handle =
        ap_register_output_filter("IRDEALFILTER",
            irdesltest_out_filter, NULL, AP_FTYPE_PROTOCOL + 1);

    ap_hook_insert_filter(irdealtest_filter_insert,
        NULL, NULL, APR_HOOK_MIDDLE);
}

함수에서 첫번째는 irdealtest_out_filter를 등록하는 부분이고, 두번째 부분은 insert_filter를 후킹해서 irdealtest_filter_insert로 넘겨주는 것이다. ap_hook_insert_filter에 대해서는 다음에 설명하자.

여튼 이렇게 irdealtest_out_filter라는 것을 아웃풋 필터로 등록했고, inser_filter를 후킹하는 함수에서 irdealtest_filter_insert를 등록했다.
irdealtest_out_filter는 다음과 같다.
static int irdealtest_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{                           
    request_rec * r = f->r;
    
    ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
        "It's in irdealtest_out_filter irdeal's message =====  %s",
        sconf->irdealmessage);
        
    return ap_pass_brigade(f->next, bb);
}

현재는 단순히 메시지만 출력한다. irdealtest_filter_insert함수에서는 irdealtest_out_filter_handle을 runtime에 집어넣는다.
static void irdealtest_filter_insert(request_rec *r)
{
    ap_add_output_filter_handle(irdealtest_out_filter_handle,
        NULL, r, r->connection);
}

모듈의 설정을 해주어야 하는데 다음과 같은 구조체를 하나 만들자.
static struct {
    char irdealtestmessage[100];
} irdealtest_conf;

그리고 그것의 초기화는 다음과 같이 create_irdealtest_config 함수에서 해준다. 
static irdealtest_conf * sconf;

static void *create_irdealtest_config(apr_pool_t *p, server_rec *s)
{
    sconf = (flvseek_conf *) apr_pcalloc(p, sizeof(flvseek_conf));
    sconf->irdealtestmessage[0] = '\0';
    return sconf;
}

설정 파일(config)을 읽어서 집어넣는것은 다음과 같이.
static const char * add_irdealmessage
    (cmd_parms * cmd, void* cfg, const char * arg)
{
    strcpy(sconf->flvident, arg);
    return NULL;
}

위의 코드들을 잘조합하면 에러파일에 메세지를 출력하는 모듈을 만들수 있다.
내용이 좀 정리가 잘안된듯하지만 차근 차근 따라하고.. 다른 모듈들은 어떻게 구현했는가 하고 비교해보면서 보다보면 알수 있을 것이다.
좀 더 세부적인 내용은 다음기회에 적기로 하겠다.
그때는 생각나는데로 조금씩 조금씩 적어볼까 한다.
한 번에 넘 많은 것을 적으려니까 숨이찬다..ㅡㅡ;

?