httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stodd...@apache.org
Subject svn commit: r109434 - /httpd/mod_arm4/trunk/mod_arm4.c
Date Thu, 02 Dec 2004 05:47:24 GMT
Author: stoddard
Date: Wed Dec  1 18:18:34 2004
New Revision: 109434

URL: http://svn.apache.org/viewcvs?view=rev&rev=109434
Log:
initial crufty version of mod_arm4.c
Added:
   httpd/mod_arm4/trunk/mod_arm4.c

Added: httpd/mod_arm4/trunk/mod_arm4.c
Url: http://svn.apache.org/viewcvs/httpd/mod_arm4/trunk/mod_arm4.c?view=auto&rev=109434
==============================================================================
--- (empty file)
+++ httpd/mod_arm4/trunk/mod_arm4.c	Wed Dec  1 18:18:34 2004
@@ -0,0 +1,878 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* INSTRUMENT_HANDLER_HACK
+ * Use arm_fixups and arm_logger as a poor man's way to call 
+ * arm_block_transaction/arm_unblock_transaction across a call to a handler. 
+ * The correct way to instrument block/unblock transactions is to modify 
+ * each handler that sends requests outside the httpd process to call the
+ * optional hooks, arm_ap_block_transaction() and arm_ap_unblock_transaction().
+ * We can selectively turn on the request for block/unblock instrumentation by
+ * setting the ArmInstrumentHandler directive inside  <Directory> or <Location>
containers.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "http_protocol.h"
+#include "util_script.h"
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_base64.h"
+#include "http_request.h"
+
+#include <stdio.h>
+
+#ifdef WIN32
+#define DEFAULT_ARM4_LIBRARY_NAME "libarm4.dll"
+#elif defined(_AIX)
+#ifdef __64BIT__
+#define DEFAULT_ARM4_LIBRARY_NAME "libarm4.a(shr_64.o)"
+#else
+#define DEFAULT_ARM4_LIBRARY_NAME "libarm4.a(shr.o)"
+#endif
+/* End AIX */
+#else
+#define DEFAULT_ARM4_LIBRARY_NAME "libarm4.so"
+#endif
+
+#include "arm4.h"
+
+#if !defined(APR_UINT64_T_HEX_FMT)
+#if defined(LINUX)
+#define APR_UINT64_T_HEX_FMT "llx"
+#elif defined(WIN32)
+#define APR_UINT64_T_HEX_FMT "I64x"
+#endif
+#endif
+
+/*
+ * Define the dynamically loadable API to the ARM client library 
+ */
+APR_DECLARE_OPTIONAL_FN(void, arm_ap_block_transaction, (const void *));
+APR_DECLARE_OPTIONAL_FN(void, arm_ap_unblock_transaction, (const void *));
+
+arm_register_application_t  ap_arm_register_application;
+arm_register_transaction_t  ap_arm_register_transaction;
+arm_register_metric_t       ap_arm_register_metric;
+arm_start_application_t     ap_arm_start_application;
+arm_stop_application_t      ap_arm_stop_application;
+arm_destroy_application_t   ap_arm_destroy_application;
+arm_start_transaction_t     ap_arm_start_transaction;
+arm_stop_transaction_t      ap_arm_stop_transaction;
+arm_update_transaction_t    ap_arm_update_transaction;
+arm_discard_transaction_t   ap_arm_discard_transaction;
+arm_block_transaction_t     ap_arm_block_transaction;
+arm_unblock_transaction_t   ap_arm_unblock_transaction;
+arm_report_transaction_t    ap_arm_report_transaction;
+arm_bind_thread_t           ap_arm_bind_thread;
+arm_unbind_thread_t         ap_arm_unbind_thread;
+arm_generate_correlator_t   ap_arm_generate_correlator;
+arm_get_correlator_length_t ap_arm_get_correlator_length;
+arm_get_correlator_flags_t  ap_arm_get_correlator_flags;
+arm_get_arrival_time_t      ap_arm_get_arrival_time;
+arm_get_error_message_t     ap_arm_get_error_message;
+arm_is_charset_supported_t  ap_arm_is_charset_supported;
+
+/* Module declaration */
+#define ARM_MODULE arm4_module
+module AP_MODULE_DECLARE_DATA ARM_MODULE;
+
+/* Per server config */
+#define DEFAULT_TRAN_NAME "HTTP Request"
+#define DEFAULT_APP_NAME  "Apache HTTP Server"
+typedef struct server_config {
+    arm_id_t app_id;
+    arm_id_t tran_id;
+    arm_app_start_handle_t app_handle;
+    const char* libname;
+
+    char *app_name;
+    char *tran_name;
+} server_config_t;
+
+/* Per dir config */
+typedef struct dir_config {
+    int instrument_handler;
+} dir_config_t;
+
+/* Per request config */
+typedef struct request_config {
+    arm_tran_start_handle_t   tran_handle;
+    arm_tran_block_handle_t   block_handle;
+    arm_subbuffer_arrival_time_t sb_arrival_time;
+} request_config_t;
+
+static int module_is_disabled = 0;
+
+/* 
+ * Convert binary data into a hex string.
+ * in  - Input data in binary format.  It's length must be len+1.
+ * out - Output data in Hex String.  It must be pre-allocated.
+ *       It's length must be at least len*2+1.
+ * len - The amount of Byte that are going to be converted.
+ */
+static void stringify(unsigned char *in, unsigned char *out, int len)
+{
+    int i;
+    char to_hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', } ;
+
+    for(i=0; i<len;i++)
+    {
+        out[2*i] = to_hex[(in[i]>>4) & 0x0f];
+        out[1+2*i] = to_hex[in[i] & 0x0f];
+    }
+
+    out[2*len] = '\0';
+}
+
+/*
+ * Convert hex String into binary data.
+ * in  - Input data in Hex String.  It's length must be len*2+1.
+ * out - Output data in binary.  It must be pre-allocated.  It's length must be
+ *       at least len+1.
+ * len - len*2+1 will be the number of byte converted.
+ */
+static void destringify(const unsigned char *in, unsigned char *out, int orig_len)
+{
+    int len=0;
+    int i;
+    int maxlen = orig_len * 2 + 1;
+
+    while((in[len] != '\0') && isxdigit(in[len]) && (len < maxlen))
+        len++;
+
+    /*
+     * if (in[len] != '\0') at this point we're ignoring trailing non xdigit chars
+     * also, len should be even, but we're not checking ...
+     */
+    for(i=0;i<(len/2);i++) {
+        if(isdigit(in[2*i])) {
+            if(isdigit(in[1+2*i])) {
+                out[i] = ((in[2*i]-'0')<<4)|(0x0f & (in[1+2*i]-'0'));
+            }
+            else  {
+                out[i] = ((in[2*i]-'0')<<4)|(0x0f & (10+toupper(in[1+2*i])-'A'));
+            }
+        }
+        else {
+            if(isdigit(in[1+2*i])) {
+                out[i] = ((10+toupper(in[2*i])-'A')<<4)|(0x0f & (in[1+2*i]-'0'));
+            }
+            else {
+                out[i] = ((10+toupper(in[2*i])-'A')<<4) |
+                                        (0x0f & (10+toupper(in[1+2*i])-'A'));
+            }
+        }
+    }
+}
+
+/*
+ *   This is to change the correlator into a string so it can be passed
+ *   in the request header to a downstream application.(Inefficient version)
+ *
+ *   Note: arm_correlator_get_length(corr_out) should be at least
+ *         2*arm_correlator_get_length(corr_in)+1
+ */
+static void stringify_Correlator(arm_correlator_t* corr_in, unsigned char* corr_out)
+{
+    unsigned char *in;
+    arm_correlator_length_t len = 0;
+    ap_arm_get_correlator_length(corr_in, &len);
+    in = (unsigned char *)corr_in;
+
+    stringify(in, corr_out, len);
+}
+
+/*
+ * pconf pool cleanup
+ */
+static apr_status_t mod_arm4_cleanup(void *dv)
+{
+    server_config_t *sconf;
+    server_rec *s = dv;
+    char *sname = s->server_hostname;
+    arm_error_t arm_rc;
+
+    sconf = ap_get_module_config(s->module_config, &arm4_module);
+    /* End the Application for this process */
+    arm_rc = ap_arm_stop_application(sconf->app_handle, 0, NULL);
+    if (arm_rc < 0) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, 
+                     "mod_arm: arm_end_application failed with rc = %d", arm_rc);
+    }
+
+    return APR_SUCCESS;
+}
+
+#define LOAD_SYMBOL(symbol) \
+{ \
+   rv = apr_dso_sym((void**)&ap_##symbol,libhandle,#symbol); \
+   if (rv != APR_SUCCESS)  { \
+      ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Failed to load symbol %s in library %s",
#symbol, libname);  \
+      return rv; \
+    } \
+}
+static apr_status_t load_library(apr_pool_t *p, server_rec *s, const char *libname)
+{
+    apr_status_t rv;
+    apr_dso_handle_t *libhandle;
+
+    rv = apr_dso_load(&libhandle, libname, p);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Failed to load library %s", libname);
+        return rv;
+    }
+
+    LOAD_SYMBOL(arm_register_application);
+    LOAD_SYMBOL(arm_register_transaction);
+    LOAD_SYMBOL(arm_register_metric);
+
+    LOAD_SYMBOL(arm_start_application);
+    LOAD_SYMBOL(arm_stop_application);
+    LOAD_SYMBOL(arm_destroy_application)
+
+    LOAD_SYMBOL(arm_start_transaction);
+    LOAD_SYMBOL(arm_stop_transaction);
+    LOAD_SYMBOL(arm_update_transaction);
+    LOAD_SYMBOL(arm_discard_transaction);
+    LOAD_SYMBOL(arm_block_transaction);
+    LOAD_SYMBOL(arm_unblock_transaction);
+    LOAD_SYMBOL(arm_report_transaction);
+
+    LOAD_SYMBOL(arm_bind_thread);
+    LOAD_SYMBOL(arm_unbind_thread);
+
+    LOAD_SYMBOL(arm_generate_correlator);
+    LOAD_SYMBOL(arm_get_correlator_length);
+    LOAD_SYMBOL(arm_get_correlator_flags);
+
+    LOAD_SYMBOL(arm_get_arrival_time);
+    LOAD_SYMBOL(arm_get_error_message);
+    LOAD_SYMBOL(arm_is_charset_supported);
+
+    /* Register a cleanup against the open handle */
+
+    return APR_SUCCESS;
+}
+
+/*
+ * Build the app_instance parameter passed on the arm_start_application()
+ * call. app_instance should be of the form:
+ * hostname/PID=pid
+ */
+static char* build_app_instance(apr_pool_t *p, server_rec *s, int max_len)
+{
+    char *app_instance;
+    char *pid_str;
+    pid_t pid = getpid();
+    
+    pid_str = apr_itoa(p, pid);
+    app_instance = apr_pstrndup(p,
+                                apr_pstrcat(p, s->server_hostname,"/PID=",pid_str,NULL),
+                                max_len);
+    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, 
+                 "mod_arm: pid: %d app_instance: %s", pid, app_instance);
+    return app_instance;
+}
+
+/* This function is called during server initialisation by each process
+ * which can serve a request. 
+ */
+static int register_application(apr_pool_t *p, server_rec *s)
+{
+    apr_status_t                    rv;
+    arm_error_t                     arm_rc;
+    server_config_t                 *sconf;
+
+    arm_buffer4_t                   cnbuf; /* context name buf */
+    arm_subbuffer_t                 *subbuf;
+    arm_subbuffer_tran_identity_t   *sb_tran_identity;
+
+    char *app_group;
+    char *app_instance;
+
+    const arm_char_t *attributes[] = {
+        "ServerVersion",
+        "HostInfo",
+        "RemoteAddress",
+        "RemoteUser",
+        "Scheme",
+        "Port",
+        "QueryString",
+        "Protocol",
+        "ServerName"
+    };
+
+    /*
+     * Set up the per process config record to hold the application and transaction
+     * type handles.
+     */
+    sconf = ap_get_module_config(s->module_config, &arm4_module);
+
+    /* Load the ARM4 client library */
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "mod_arm: Loading the ARM4 client library
%s", sconf->libname);
+    rv = load_library(p, s, sconf->libname);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 
+                     "mod_arm: Failed to load the ARM4 client library %s. mod_arm4_ap20 is
disabled.", 
+                     sconf->libname);
+        module_is_disabled = 1;
+        return OK;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "mod_arm: Initializing ARM client.");
+
+    /* 
+     * Register application class with arm agent 
+     */
+    arm_rc = ap_arm_register_application(sconf->app_name, ARM_ID_NONE, 
+                                         ARM_FLAG_NONE, ARM_BUF4_NONE,
+                                         &(sconf->app_id));
+    if (arm_rc < 0) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 
+                     "mod_arm: arm_register_application() failed with rc = %d. mod_arm4_ap20
is disabled.", arm_rc);
+        module_is_disabled = 1;
+        return OK;
+    }
+
+    /* Register the cleanup which calls arm_stop_application() when pconf 
+     * is destroyed 
+     */
+    apr_pool_cleanup_register(p, s, mod_arm4_cleanup, apr_pool_cleanup_null);
+
+    /* Register transaction class with arm agent. Begin by setting up the 
+     * transaction type buffer
+     */
+    sb_tran_identity = apr_pcalloc(p, sizeof(*sb_tran_identity));
+
+    sb_tran_identity->header.format = ARM_SUBBUFFER_TRAN_IDENTITY;
+    sb_tran_identity->identity_property_count = 0;
+    sb_tran_identity->identity_property_array = NULL;
+    sb_tran_identity->context_name_count = 9;
+    sb_tran_identity->context_name_array = &attributes[0];
+    sb_tran_identity->uri = NULL;
+
+    subbuf = (arm_subbuffer_t *) sb_tran_identity;
+    cnbuf.count = 1;
+    cnbuf.subbuffer_array = &subbuf;
+
+    arm_rc = ap_arm_register_transaction(&(sconf->app_id),
+                                         sconf->tran_name,
+                                         ARM_ID_NONE,
+                                         ARM_FLAG_NONE, 
+                                         &cnbuf,
+                                         &(sconf->tran_id));
+    if (arm_rc < 0) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 
+                     "mod_arm: arm_register_transaction() failed with rc = %d. mod_arm4_ap20
is disabled", arm_rc);
+        module_is_disabled = 1;
+        return OK;
+    }
+ 
+    /* Start the application instance
+     */
+    app_group = apr_pstrndup(p,ap_get_server_version(),ARM_PROPERTY_VALUE_MAX_CHARS);
+    app_instance = build_app_instance(p, s, ARM_PROPERTY_VALUE_MAX_CHARS);
+    arm_rc = ap_arm_start_application(&(sconf->app_id),
+                                      app_group,
+                                      app_instance,
+                                      ARM_FLAG_NONE, 
+                                      ARM_BUF4_NONE,
+                                      &(sconf->app_handle));
+    if (arm_rc < 0) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 
+                     "mod_arm: arm_start_application() failed with rc = %d. mod_arm4_ap20
is disabled", arm_rc);
+        module_is_disabled = 1;
+        return OK;
+    }
+ 
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "mod_arm: ARM client initialized for server
%s", s->server_hostname);
+
+    return OK;
+}
+static void arm_child_init(apr_pool_t *p, server_rec *s)
+{
+    register_application(p, s);
+}
+
+/*
+ * This function gets called to create a per-server configuration
+ * record.  It will always be called for the "default" server.
+ *
+ * The return value is a pointer to the created module-specific
+ * structure.
+ */
+static void *arm_create_server_config(apr_pool_t *p, server_rec *s)
+{
+    server_config_t *sconf;
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 
+                 "mod_arm: Entering arm_create_server_config()");
+
+    sconf = (server_config_t *) apr_pcalloc(p, sizeof(*sconf));
+    sconf->libname = DEFAULT_ARM4_LIBRARY_NAME;
+    sconf->tran_name = DEFAULT_TRAN_NAME;
+    sconf->app_name = DEFAULT_APP_NAME;
+    return sconf;
+}
+
+/* Create the per-dir config
+ */
+static void *arm_create_dir_config(apr_pool_t *p, char *s)
+{
+    dir_config_t *dconf =  apr_pcalloc(p, sizeof (dir_config_t));
+    dconf->instrument_handler = 0;
+    return dconf;
+}
+static void *arm_merge_dir_config(apr_pool_t *p, void *basev, void *addv)
+{
+    dir_config_t *base = (dir_config_t*) basev;
+    dir_config_t *add = (dir_config_t*) addv;
+    dir_config_t *new = apr_pcalloc(p, sizeof(dir_config_t));
+
+    new->instrument_handler = add->instrument_handler;
+    return new;
+}
+
+/*
+ * This function is a request pool cleanup to notify the ARM agent
+ * the transaction has ended.
+ */
+static apr_status_t stop_transaction(void *arg)
+{
+    request_rec *r = (request_rec *) arg;
+    arm_error_t arm_rc;
+    arm_tran_status_t tran_status;
+    request_config_t *rconf;
+
+#if 0
+    /* This check was needed when this code was called during the
+     * logging phase. Leave in for documentation.
+     */
+    if (module_is_disabled) {
+        return DECLINED;
+    }
+#endif
+
+    rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
+
+    if (r->status >= 500) {
+        tran_status = ARM_STATUS_ABORTED;   /* Server errors */
+    }
+    else if (r->status >= 400) {
+        tran_status = ARM_STATUS_FAILED;    /* Client Errors */
+    }
+    else {
+        tran_status = ARM_STATUS_GOOD;      /* No Error */
+    }
+
+    arm_rc = ap_arm_stop_transaction(rconf->tran_handle,
+                                     tran_status,
+                                     0,
+                                     NULL);
+
+    if (arm_rc < 0) {
+        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 
+                      "mod_arm4: arm_stop_transaction() failed with rc: %x "
+                      "Start handle: %"APR_UINT64_T_HEX_FMT"", arm_rc, rconf->tran_handle);
+    }
+    else {
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 
+                      "mod_arm4: arm_stop_transaction() handle: %"APR_UINT64_T_HEX_FMT",
rc: %x", 
+                      rconf->tran_handle, arm_rc);
+    }
+    return APR_SUCCESS;
+}
+
+/* Record the HTTP request arrival time for use in the arm_start_transaction()
+ * call made after all access/auth checks have been made
+ */
+static int arm_post_read_request(request_rec *r)
+{
+    request_config_t *rconf;
+
+    if (module_is_disabled) {
+        return DECLINED;
+    }
+
+    /* Set up the per-request config structure */
+    rconf = apr_pcalloc(r->pool, sizeof(*rconf));
+    rconf->sb_arrival_time.header.format = ARM_SUBBUFFER_ARRIVAL_TIME;
+    ap_arm_get_arrival_time(&(rconf->sb_arrival_time.opaque_time));
+
+    ap_set_module_config(r->request_config, &arm4_module, rconf); 
+
+    return DECLINED;
+}
+
+/* ArmLoadLibrary <library name>
+ */
+static const char *arm_load_library(cmd_parms *parms, 
+                                    void *dummy, 
+                                    const char *arg)
+{
+    server_config_t *sconf;
+    char *libname;
+    const char *c;
+
+    sconf = ap_get_module_config(parms->server->module_config, &arm4_module);
+    if (!arg) {
+        return "ArmLoadLibrary requires an ARM library name as an argument";
+    }
+    libname = apr_pstrdup(parms->pool, arg);
+
+    c = strrchr(arg, '.');
+#ifdef _AIX
+    /* AIX presents it's shared objects in an archive file. Tweak the libname
+     * argument appropriately 
+     */
+    if (c && !strcasecmp(c, ".a")) {
+#ifdef __64BIT__
+        libname = apr_pstrcat(parms->pool, arg, "(shr_64.o)", NULL);
+#else
+        libname = apr_pstrcat(parms->pool, arg, "(shr.o)", NULL);
+#endif
+    }
+#endif
+
+    sconf->libname = libname;
+    return NULL;
+}
+
+/* ArmTransactionName <name>
+ */
+static const char *arm_set_transaction_name(cmd_parms *parms, void *d, const char *arg)
+{
+    server_config_t *sconf = ap_get_module_config(parms->server->module_config, &arm4_module);
+    sconf->tran_name = apr_pstrdup(parms->pool, arg);
+    return NULL;
+}
+
+/* ArmApplicationName <name>
+ */
+static const char *arm_set_application_name(cmd_parms *parms, void *d, const char *arg)
+{
+    server_config_t *sconf = ap_get_module_config(parms->server->module_config, &arm4_module);
+    sconf->app_name = apr_pstrdup(parms->pool, arg);
+    return NULL;
+}
+
+/* ArmInstrumentHandler on|off
+ */
+static const char *arm_instrument_handler(cmd_parms *parms, void *dconfv, const char *arg)
+{
+    dir_config_t *dconf = (dir_config_t *) dconfv;
+
+    if (!strcasecmp(arg, "on")) {
+        dconf->instrument_handler = 1;
+    }
+    else {
+        dconf->instrument_handler = 0;
+    }
+    return NULL;
+}
+
+static const command_rec arm_commands[] = {
+    AP_INIT_TAKE1("ArmLoadLibrary", arm_load_library, NULL, RSRC_CONF | EXEC_ON_READ,
+      "the name of the ARM4 agent shared library."),
+    AP_INIT_TAKE1("ArmTransactionName", arm_set_transaction_name, NULL, RSRC_CONF | EXEC_ON_READ,
+      "the transaction name registered with the ARM agent. Default: HTTP Request"),
+    AP_INIT_TAKE1("ArmApplicationName", arm_set_application_name, NULL, RSRC_CONF | EXEC_ON_READ,
+      "the application name registered with the the ARM agent. Default: Apache HTTP Server"),
+    AP_INIT_TAKE1("ArmInstrumentHandler", arm_instrument_handler, NULL, RSRC_CONF | ACCESS_CONF,
+      "on|off. ArmInstrumentHandler on causes arm_block|unblock_transaction to be called
across content handlers. Default: off"),
+    { NULL }
+};
+void arm_ap_unblock_transaction(const void *vr)
+{
+    arm_error_t arm_rc;
+    request_config_t *rconf;
+    request_rec *r = (request_rec *) vr;
+
+    if (module_is_disabled) {
+        return;
+    }
+
+    rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
   
+    if (!rconf) {
+        /* We can hit this case while processing a subrequest. Checking for rconf
+         * NULL is faster check than checking for subrequest
+         */
+        return;
+    }
+    arm_rc = ap_arm_unblock_transaction(rconf->tran_handle, rconf->block_handle, 0,
NULL);
+
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                  "mod_arm4: arm_unblocked_transaction() handle:  %"APR_UINT64_T_HEX_FMT",
"     
+                  "block_handle: %"APR_UINT64_T_HEX_FMT", rc: %x",     
+                  rconf->tran_handle, rconf->block_handle, arm_rc);
+
+    return;
+}
+
+/*
+ * Begin definition of optional functions. These functions are used to enable a module to
+ * interface to the ARM client w/o needing to be responsible for making sure the ARM client
+ * library is loaded, initialized, etc.
+ */
+void arm_ap_block_transaction(const void *vr)
+{
+    arm_error_t arm_rc;
+    request_rec *r = (request_rec*) vr;
+    request_config_t *rconf;
+    /*    arm_tran_block_handle_t *block_handle = apr_pcalloc(r->pool, sizeof(arm_tran_block_handle_t));
*/
+
+    if (module_is_disabled) {
+        return;
+    }
+    rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
+    if (!rconf) {
+        /* We can hit this case while processing a subrequest. Checking for rconf
+         * NULL is faster check than checking for subrequest
+         */
+        return;
+    }
+
+    arm_rc = ap_arm_block_transaction(rconf->tran_handle, 0, NULL, &rconf->block_handle);
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                  "mod_arm4: arm_block_transaction() handle:  %"APR_UINT64_T_HEX_FMT", "
    
+                  "block_handle: %"APR_UINT64_T_HEX_FMT", rc: %x",     
+                  rconf->tran_handle, rconf->block_handle, arm_rc);
+    return;
+}
+
+/* arm_fixups:
+ * Call arm_start_transaction() in this hook rather than in post_read_request
+ * because RemoteUser is not known until after access/auth checks have been 
+ * run.
+ */
+static int arm_fixups(request_rec *r)
+{
+    dir_config_t     *dconf;
+    server_config_t  *sconf;
+    request_config_t *rconf;
+    arm_error_t arm_rc;
+    apr_uri_t uri_parts;
+
+    unsigned char *stringified_correlator;
+    const char *stringified_parent_correlator;
+    arm_correlator_t *correlator;
+    arm_correlator_t *parent_correlator;
+
+    const arm_char_t *attribvalues[9];
+    arm_buffer4_t cvbuf;  
+    arm_subbuffer_t *subbuf[2];
+    arm_subbuffer_tran_context_t *sb_tran_values;
+
+    if (module_is_disabled) {
+        return DECLINED;
+    }
+
+    /* Start the request only the first time we see it. If we see it again
+     * after alias or redirect we don't want to start another one. If you'd
+     * rather do classification on the aliased or redirected URL you'll have
+     * to change this.
+     */
+    if (!ap_is_initial_req(r)) {
+        return DECLINED;
+    }
+    sconf = ap_get_module_config(r->server->module_config, &arm4_module);
+
+    rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
   
+    if (!rconf) {
+        /* We can hit this case while processing a subrequest. Checking for rconf
+         * NULL is faster check than checking for subrequest
+         */
+        return DECLINED;
+    }
+
+    /* Initialize the arm_subbuffer_tran_context_t
+     */
+    apr_uri_parse(r->pool, ap_construct_url(r->pool,r->uri,r), &uri_parts);
+    attribvalues[0] = apr_pstrdup(r->pool, ap_get_server_version());
+    attribvalues[1] = uri_parts.hostinfo;
+    attribvalues[2] = r->connection->remote_ip;
+    attribvalues[3] = r->user;
+    attribvalues[4] = uri_parts.scheme;
+    attribvalues[5] = apr_psprintf(r->pool, "%u", ap_get_server_port(r));
+    attribvalues[6] = apr_pstrdup(r->pool, r->args); /* Query string */
+    attribvalues[7] = "HTTP 1.1"; /* Protocol */
+    attribvalues[8] = ap_get_server_name(r);
+
+    sb_tran_values = apr_pcalloc(r->pool, sizeof(*sb_tran_values));
+    sb_tran_values->header.format = ARM_SUBBUFFER_TRAN_CONTEXT;
+    sb_tran_values->context_value_count = 9;
+    sb_tran_values->context_value_array = &attribvalues[0];
+    sb_tran_values->uri = r->uri;
+    subbuf[0] = (arm_subbuffer_t *) sb_tran_values;
+
+    /* arm_subbuffer_arrival_time_t was initialized in the post_read_request hook
+     */
+    subbuf[1] = (arm_subbuffer_t *) &rconf->sb_arrival_time;
+
+    cvbuf.count = 2;
+    cvbuf.subbuffer_array = &subbuf[0];
+
+    correlator = (arm_correlator_t *) apr_pcalloc(r->pool, ARM_CORR_MAX_LENGTH);
+
+    /* Check for an ARM_CORRELATOR header field on the inbound request, set the
+     * parent_correlator.
+     */
+    parent_correlator = NULL;
+    stringified_parent_correlator = apr_table_get(r->headers_in, "ARM_CORRELATOR");
+    if (stringified_parent_correlator) {
+        int len;
+
+        /* Do some simple validity checks on the correlator string. Ignore invalid
+         * correlators.
+         */
+        len = strlen(stringified_parent_correlator);
+        if (len > 2*ARM_CORR_MAX_LENGTH) {
+            /* Length error: exceeded max len */
+            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+                          "mod_arm: Inbound ARM_CORRELATOR failed length check. Length is
%d. Correlator: %s ...",
+                          len, apr_pstrndup(r->pool, stringified_parent_correlator, 20));
+        }
+        else if (len % 2) {
+            /* Length error: odd length */
+            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+                          "mod_arm: Inbound ARM_CORRELATOR failed length check. Correlator
contains odd number of characters. Correlator: %s ...",
+                          apr_pstrndup(r->pool, stringified_parent_correlator, 20));
+        }
+        else {
+            len = (len/2);
+            parent_correlator = (arm_correlator_t *) apr_pcalloc(r->pool, ARM_CORR_MAX_LENGTH);
+            destringify((const unsigned char*)stringified_parent_correlator, (unsigned char*)
parent_correlator, len);
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "mod_arm: Received ARM_CORRELATOR header field. Correlator: %s
...",
+                          apr_pstrndup(r->pool, stringified_parent_correlator, 20));
+        }
+    }
+
+    /* ARM_FLAG_BIND_THREAD is only valid if the same thread calls 
+     * arm_start_transaction() and arm_stop_transaction(). This assumption
+     * breaks when httpd supports non-blocking event driven or async 
+     * i/o.
+     */
+    arm_rc = ap_arm_start_transaction(sconf->app_handle,
+                                      &(sconf->tran_id),
+                                      parent_correlator,
+                                      ARM_FLAG_BIND_THREAD,
+                                      &cvbuf,
+                                      &rconf->tran_handle,
+                                      correlator);
+    if (arm_rc < 0) {
+        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 
+                      "mod_arm: arm_start_transaction() failed with rc = %x", arm_rc);
+    }
+    else {
+        /* Register the stop_transaction only if the call to 
+         * start_transaction is successful.
+         */
+        apr_pool_cleanup_register(r->pool, r, stop_transaction, 
+                                  apr_pool_cleanup_null);
+        stringified_correlator = (unsigned char *) apr_pcalloc(r->pool, (2*ARM_CORR_MAX_LENGTH+1));
+        stringify_Correlator(correlator, stringified_correlator);
+    }
+
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                  "mod_arm4: arm_start_transaction() handle: %"APR_UINT64_T_HEX_FMT", rc:
%x\n"
+                  "\tcorrelator: %s\n"
+                  "\tconstructed url: %s\n"
+                  "\tattr::ServerVersion: %s\n"
+                  "\tattr::Hostinfo: %s\n"
+                  "\tattr::RemoteAddress: %s\n"
+                  "\tattr::RemoteUser: %s\n"
+                  "\tattr::Scheme: %s\n"
+                  "\tattr::Port: %s\n"
+                  "\tattr::QueryString: %s\n"
+                  "\tattr::Protocol: %s\n"
+                  "\tattr::ServerName: %s\n",
+                  rconf->tran_handle, arm_rc, 
+                  stringified_correlator, 
+                  ap_construct_url(r->pool, r->uri, r),
+                  attribvalues[0], 
+                  attribvalues[1], 
+                  attribvalues[2], 
+                  attribvalues[3], 
+                  attribvalues[4],
+                  attribvalues[5],
+                  attribvalues[6],
+                  attribvalues[7],
+                  attribvalues[8]);
+
+    /* TODO: Develop config driven or huristic for when to add the ARM_CORRELATOR.
+     * For now, always add the correlator.
+     */
+    apr_table_set(r->headers_in, "ARM_CORRELATOR", (char*) stringified_correlator);
+    apr_table_set(r->err_headers_out, "ARM_CORRELATOR", (char*) stringified_correlator);
/* Is this necessary? */
+
+    /* Poor man's way to bracket the call to the handler with
+     * arm_block_transaction()/arm_unblock_transaction() calls. The 
+     * arm_unblock_transaction() is called in the logging phase.  If you
+     * can live with the potential inacuracies with this method, you can
+     * eliminate the need to instrument each and every handler with block/unblock
+     * calls.
+     */
+    dconf = (dir_config_t *) ap_get_module_config(r->per_dir_config, &arm4_module);
+    if (dconf->instrument_handler) {
+        arm_ap_block_transaction(r);
+    }
+    return DECLINED;
+}
+
+/* arm_logger(): poor man's arm_unblock_tranaction()
+ * TODO: Consider implementing this call in a simple output filter that
+ *       sets high in the stack.
+ */
+static int arm_logger(request_rec *r)
+{
+    dir_config_t *dconf;
+
+    if (module_is_disabled) {
+        return DECLINED;
+    }
+    dconf = (dir_config_t *) ap_get_module_config(r->per_dir_config, &arm4_module);
+    if (dconf->instrument_handler) {
+        arm_ap_unblock_transaction(r);
+    }
+    return DECLINED;
+}
+
+
+static void arm_register_hooks(apr_pool_t *p)
+{
+    ap_hook_fixups(arm_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST);
+    ap_hook_log_transaction(arm_logger, NULL, NULL, APR_HOOK_LAST);
+    ap_hook_post_read_request(arm_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_child_init(arm_child_init, NULL, NULL, APR_HOOK_MIDDLE);
+    APR_REGISTER_OPTIONAL_FN(arm_ap_block_transaction);
+    APR_REGISTER_OPTIONAL_FN(arm_ap_unblock_transaction);
+}
+
+module AP_MODULE_DECLARE_DATA ARM_MODULE =
+{
+    STANDARD20_MODULE_STUFF,
+    arm_create_dir_config,      /* per-directory config creator */
+    arm_merge_dir_config,       /* dir config merger */
+    arm_create_server_config,   /* server config creator */
+    NULL,                       /* server config merger */
+    arm_commands,               /* command table */
+    arm_register_hooks,         /* register hooks*/
+};

Mime
View raw message