/[Apache-SVN]/httpd/sandbox/mod_arm4/mod_arm4.c
ViewVC logotype

Contents of /httpd/sandbox/mod_arm4/mod_arm4.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 653637 - (show annotations) (download)
Mon May 5 23:50:48 2008 UTC (16 years, 3 months ago) by fielding
File MIME type: text/plain
File size: 34274 byte(s)
moving mod_arm4 to sandbox
1 /* Copyright 2000-2004 The Apache Software Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /* INSTRUMENT_HANDLER_HACK
17 * Use arm_fixups and arm_logger as a poor man's way to call
18 * arm_block_transaction/arm_unblock_transaction across a call to a handler.
19 * The correct way to instrument block/unblock transactions is to modify
20 * each handler that sends requests outside the httpd process to call the
21 * optional hooks, arm_ap_block_transaction() and arm_ap_unblock_transaction().
22 * We can selectively turn on the request for block/unblock instrumentation by
23 * setting the ArmInstrumentHandler directive inside <Directory> or <Location> containers.
24 */
25
26 #include "httpd.h"
27 #include "http_config.h"
28 #include "http_core.h"
29 #include "http_log.h"
30 #include "http_main.h"
31 #include "http_protocol.h"
32 #include "util_script.h"
33 #include "apr.h"
34 #include "apr_strings.h"
35 #include "apr_base64.h"
36 #include "http_request.h"
37 #include "mod_arm4.h"
38 #include <stdio.h>
39
40 #ifdef WIN32
41 #define DEFAULT_ARM4_LIBRARY_NAME "libarm4.dll"
42 #elif defined(_AIX)
43 #ifdef __64BIT__
44 #define DEFAULT_ARM4_LIBRARY_NAME "libarm4.a(shr_64.o)"
45 #else
46 #define DEFAULT_ARM4_LIBRARY_NAME "libarm4.a(shr.o)"
47 #endif
48 /* End AIX */
49 #else
50 #define DEFAULT_ARM4_LIBRARY_NAME "libarm4.so"
51 #endif
52
53 #include "arm4.h"
54
55 #if !defined(APR_UINT64_T_HEX_FMT)
56 #if defined(LINUX)
57 #define APR_UINT64_T_HEX_FMT "llx"
58 #elif defined(WIN32)
59 #define APR_UINT64_T_HEX_FMT "I64x"
60 #endif
61 #endif
62
63 /*
64 * Define the dynamically loadable API to the ARM client library
65 */
66 APR_DECLARE_OPTIONAL_FN(void, arm_ap_block_transaction, (const void *));
67 APR_DECLARE_OPTIONAL_FN(void, arm_ap_unblock_transaction, (const void *));
68
69 arm_register_application_t ap_arm_register_application;
70 arm_register_transaction_t ap_arm_register_transaction;
71 arm_register_metric_t ap_arm_register_metric;
72 arm_start_application_t ap_arm_start_application;
73 arm_stop_application_t ap_arm_stop_application;
74 arm_destroy_application_t ap_arm_destroy_application;
75 arm_start_transaction_t ap_arm_start_transaction;
76 arm_stop_transaction_t ap_arm_stop_transaction;
77 arm_update_transaction_t ap_arm_update_transaction;
78 arm_discard_transaction_t ap_arm_discard_transaction;
79 arm_block_transaction_t ap_arm_block_transaction;
80 arm_unblock_transaction_t ap_arm_unblock_transaction;
81 arm_report_transaction_t ap_arm_report_transaction;
82 arm_bind_thread_t ap_arm_bind_thread;
83 arm_unbind_thread_t ap_arm_unbind_thread;
84 arm_generate_correlator_t ap_arm_generate_correlator;
85 arm_get_correlator_length_t ap_arm_get_correlator_length;
86 arm_get_correlator_flags_t ap_arm_get_correlator_flags;
87 arm_get_arrival_time_t ap_arm_get_arrival_time;
88 arm_get_error_message_t ap_arm_get_error_message;
89 arm_is_charset_supported_t ap_arm_is_charset_supported;
90
91 /* Module declaration */
92 #define ARM_MODULE arm4_module
93 module AP_MODULE_DECLARE_DATA ARM_MODULE;
94
95 /* Per server config */
96 #define DEFAULT_TRAN_NAME "HTTP Request"
97 #define DEFAULT_APP_NAME "Apache HTTP Server"
98 #define DEFAULT_PLUGINTYPE "Apache"
99 typedef struct server_config {
100 arm_id_t app_id;
101 arm_id_t tran_id;
102 arm_app_start_handle_t app_handle;
103 const char* libname;
104
105 char *app_name;
106 char *tran_name;
107 } server_config_t;
108
109 /* Per dir config */
110 typedef struct dir_config {
111 int instrument_handler;
112 } dir_config_t;
113
114 /* Per request config */
115 typedef struct request_config {
116 arm_tran_start_handle_t tran_handle;
117 arm_tran_block_handle_t block_handle;
118 arm_subbuffer_arrival_time_t sb_arrival_time;
119 } request_config_t;
120
121 static int module_is_disabled = 0;
122
123 /*
124 * Convert binary data into a hex string.
125 * in - Input data in binary format. It's length must be len+1.
126 * out - Output data in Hex String. It must be pre-allocated.
127 * It's length must be at least len*2+1.
128 * len - The amount of Byte that are going to be converted.
129 */
130 static void stringify(unsigned char *in, unsigned char *out, int len)
131 {
132 int i;
133 char to_hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
134 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', } ;
135
136 for(i=0; i<len;i++) {
137 out[2*i] = to_hex[(in[i]>>4) & 0x0f];
138 out[1+2*i] = to_hex[in[i] & 0x0f];
139 }
140
141 out[2*len] = '\0';
142 }
143
144 /*
145 * Convert hex String into binary data.
146 * in - Input data in Hex String. It's length must be len*2+1.
147 * out - Output data in binary. It must be pre-allocated. It's length must be
148 * at least len+1.
149 * len - len*2+1 will be the number of byte converted.
150 */
151 static void destringify(const unsigned char *in, unsigned char *out, int orig_len)
152 {
153 int len=0;
154 int i;
155 int maxlen = orig_len * 2 + 1;
156
157 while((in[len] != '\0') && isxdigit(in[len]) && (len < maxlen)) {
158 len++;
159 }
160
161 /*
162 * if (in[len] != '\0') at this point we're ignoring trailing non xdigit chars
163 * also, len should be even, but we're not checking ...
164 */
165 for(i=0;i<(len/2);i++) {
166 if(isdigit(in[2*i])) {
167 if(isdigit(in[1+2*i])) {
168 out[i] = ((in[2*i]-'0')<<4)|(0x0f & (in[1+2*i]-'0'));
169 }
170 else {
171 out[i] = ((in[2*i]-'0')<<4)|(0x0f & (10+toupper(in[1+2*i])-'A'));
172 }
173 }
174 else {
175 if(isdigit(in[1+2*i])) {
176 out[i] = ((10+toupper(in[2*i])-'A')<<4)|(0x0f & (in[1+2*i]-'0'));
177 }
178 else {
179 out[i] = ((10+toupper(in[2*i])-'A')<<4) |
180 (0x0f & (10+toupper(in[1+2*i])-'A'));
181 }
182 }
183 }
184 }
185
186 /*
187 * This is to change the correlator into a string so it can be passed
188 * in the request header to a downstream application.(Inefficient version)
189 *
190 * Note: arm_correlator_get_length(corr_out) should be at least
191 * 2*arm_correlator_get_length(corr_in)+1
192 */
193 static void stringify_Correlator(arm_correlator_t* corr_in, unsigned char* corr_out)
194 {
195 unsigned char *in;
196 arm_correlator_length_t len = 0;
197 ap_arm_get_correlator_length(corr_in, &len);
198 in = (unsigned char *)corr_in;
199
200 stringify(in, corr_out, len);
201 }
202
203 /*
204 * pconf pool cleanup
205 */
206 static apr_status_t mod_arm4_cleanup(void *dv)
207 {
208 server_config_t *sconf;
209 server_rec *s = dv;
210 char *sname = s->server_hostname;
211 arm_error_t arm_rc;
212
213 sconf = ap_get_module_config(s->module_config, &arm4_module);
214 /* End the Application for this process */
215 arm_rc = ap_arm_stop_application(sconf->app_handle, 0, NULL);
216 if (arm_rc < 0) {
217 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
218 "mod_arm: arm_stop_application failed with rc = %d", arm_rc);
219 }
220 /** app must be destroyed */
221 arm_rc = ap_arm_destroy_application(&(sconf->app_id), 0, NULL);
222 if (arm_rc < 0) {
223 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
224 "mod_arm: arm_destroy_application failed with rc = %d", arm_rc);
225 }
226
227 return APR_SUCCESS;
228 }
229
230 #define LOAD_SYMBOL(symbol) \
231 { \
232 rv = apr_dso_sym((void**)&ap_##symbol,libhandle,#symbol); \
233 if (rv != APR_SUCCESS) { \
234 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Failed to load symbol %s in library %s", #symbol, libname); \
235 return rv; \
236 } \
237 }
238 static apr_status_t load_library(apr_pool_t *p, server_rec *s, const char *libname)
239 {
240 apr_status_t rv;
241 apr_dso_handle_t *libhandle;
242
243 rv = apr_dso_load(&libhandle, libname, p);
244 if (rv != APR_SUCCESS) {
245 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "Failed to load library %s", libname);
246 return rv;
247 }
248
249 LOAD_SYMBOL(arm_register_application);
250 LOAD_SYMBOL(arm_register_transaction);
251 LOAD_SYMBOL(arm_register_metric);
252
253 LOAD_SYMBOL(arm_start_application);
254 LOAD_SYMBOL(arm_stop_application);
255 LOAD_SYMBOL(arm_destroy_application)
256
257 LOAD_SYMBOL(arm_start_transaction);
258 LOAD_SYMBOL(arm_stop_transaction);
259 LOAD_SYMBOL(arm_update_transaction);
260 LOAD_SYMBOL(arm_discard_transaction);
261 LOAD_SYMBOL(arm_block_transaction);
262 LOAD_SYMBOL(arm_unblock_transaction);
263 LOAD_SYMBOL(arm_report_transaction);
264
265 LOAD_SYMBOL(arm_bind_thread);
266 LOAD_SYMBOL(arm_unbind_thread);
267
268 LOAD_SYMBOL(arm_generate_correlator);
269 LOAD_SYMBOL(arm_get_correlator_length);
270 LOAD_SYMBOL(arm_get_correlator_flags);
271
272 LOAD_SYMBOL(arm_get_arrival_time);
273 LOAD_SYMBOL(arm_get_error_message);
274 LOAD_SYMBOL(arm_is_charset_supported);
275
276 /* Register a cleanup against the open handle */
277
278 return APR_SUCCESS;
279 }
280
281 /*
282 * Build the app_instance parameter passed on the arm_start_application()
283 * call. app_instance should be of the form:
284 * hostname/PID=pid
285 */
286 static char* build_app_instance(apr_pool_t *p, server_rec *s, int max_len)
287 {
288 char *app_instance;
289 char *pid_str;
290 pid_t pid = getpid();
291
292 pid_str = apr_itoa(p, pid);
293 app_instance = apr_pstrndup(p,
294 apr_pstrcat(p, s->server_hostname,"/PID=",pid_str,NULL),
295 max_len);
296 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
297 "mod_arm: pid: %d app_instance: %s", pid, app_instance);
298 return app_instance;
299 }
300
301 /* This function is called during server initialisation by each process
302 * which can serve a request.
303 */
304 static int register_application(apr_pool_t *p, server_rec *s)
305 {
306 apr_status_t rv;
307 arm_error_t arm_rc;
308 server_config_t *sconf;
309
310 arm_buffer4_t api_buff4; /*ARM buffer4*/
311 arm_subbuffer_t *subbuf;
312 arm_subbuffer_app_identity_t *sb_appl_identity;
313 arm_subbuffer_tran_identity_t *sb_tran_identity;
314
315 char *app_group;
316 char *app_instance;
317
318 arm_property_t appl_identity_properties[1];
319
320 const arm_char_t *tran_context_names[] = {
321 "ServerVersion",
322 "HostInfo",
323 "RemoteAddress",
324 "RemoteUser",
325 "Scheme",
326 "Port",
327 "QueryString",
328 "Protocol",
329 "ServerName"
330 };
331
332 /*
333 * Set up the per process config record to hold the application and transaction
334 * type handles.
335 */
336 sconf = ap_get_module_config(s->module_config, &arm4_module);
337
338 /* Load the ARM4 client library */
339 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "mod_arm: Loading the ARM4 client library %s", sconf->libname);
340 rv = load_library(p, s, sconf->libname);
341 if (rv != APR_SUCCESS) {
342 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
343 "mod_arm: Failed to load the ARM4 client library %s. mod_arm4_ap20 is disabled.",
344 sconf->libname);
345 module_is_disabled = 1;
346 return OK;
347 }
348
349 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "mod_arm: Initializing ARM client.");
350
351 /*
352 * Register application class with arm agent
353 */
354 appl_identity_properties[0].name = "PluginType";
355 appl_identity_properties[0].value = DEFAULT_PLUGINTYPE;
356
357 sb_appl_identity = apr_pcalloc(p, sizeof(*sb_appl_identity));
358
359 sb_appl_identity->header.format = ARM_SUBBUFFER_APP_IDENTITY;
360 sb_appl_identity->identity_property_count = 1;
361 sb_appl_identity->identity_property_array = &appl_identity_properties[0];
362 sb_appl_identity->context_name_count = 0;
363 sb_appl_identity->context_name_array = NULL;
364
365 subbuf = (arm_subbuffer_t *) sb_appl_identity;
366 api_buff4.count = 1;
367 api_buff4.subbuffer_array = &subbuf;
368
369 arm_rc = ap_arm_register_application(sconf->app_name, ARM_ID_NONE,
370 ARM_FLAG_NONE, &api_buff4,
371 &(sconf->app_id));
372 if (arm_rc < 0) {
373 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
374 "mod_arm: arm_register_application() failed with rc = %d. mod_arm4_ap20 is disabled.",
375 arm_rc);
376 module_is_disabled = 1;
377 return OK;
378 }
379
380 /* Register the cleanup which calls arm_stop_application() when pconf
381 * is destroyed
382 */
383 apr_pool_cleanup_register(p, s, mod_arm4_cleanup, apr_pool_cleanup_null);
384
385 /* Register transaction class with arm agent. Begin by setting up the
386 * transaction type buffer
387 */
388 sb_tran_identity = apr_pcalloc(p, sizeof(*sb_tran_identity));
389
390 sb_tran_identity->header.format = ARM_SUBBUFFER_TRAN_IDENTITY;
391 sb_tran_identity->identity_property_count = 0;
392 sb_tran_identity->identity_property_array = NULL;
393 sb_tran_identity->context_name_count = 9;
394 sb_tran_identity->context_name_array = &tran_context_names[0];
395 sb_tran_identity->uri = NULL;
396
397 subbuf = (arm_subbuffer_t *) sb_tran_identity;
398 api_buff4.count = 1;
399 api_buff4.subbuffer_array = &subbuf;
400
401 arm_rc = ap_arm_register_transaction(&(sconf->app_id),
402 sconf->tran_name,
403 ARM_ID_NONE,
404 ARM_FLAG_NONE,
405 &api_buff4,
406 &(sconf->tran_id));
407 if (arm_rc < 0) {
408 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
409 "mod_arm: arm_register_transaction() failed with rc = %d. mod_arm4_ap20 is disabled",
410 arm_rc);
411 module_is_disabled = 1;
412 return OK;
413 }
414
415 /* Start the application instance
416 */
417 app_group = apr_pstrndup(p,ap_get_server_version(),ARM_PROPERTY_VALUE_MAX_CHARS);
418 app_instance = build_app_instance(p, s, ARM_PROPERTY_VALUE_MAX_CHARS);
419 arm_rc = ap_arm_start_application(&(sconf->app_id),
420 app_group,
421 app_instance,
422 ARM_FLAG_NONE,
423 ARM_BUF4_NONE,
424 &(sconf->app_handle));
425 if (arm_rc < 0) {
426 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
427 "mod_arm: arm_start_application() failed with rc = %d. mod_arm4_ap20 is disabled", arm_rc);
428 module_is_disabled = 1;
429 return OK;
430 }
431
432 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "mod_arm: ARM client initialized for server %s",
433 s->server_hostname);
434
435 return OK;
436 }
437 static void arm_child_init(apr_pool_t *p, server_rec *s)
438 {
439 register_application(p, s);
440 }
441
442 /*
443 * This function gets called to create a per-server configuration
444 * record. It will always be called for the "default" server.
445 *
446 * The return value is a pointer to the created module-specific
447 * structure.
448 */
449 static void *arm_create_server_config(apr_pool_t *p, server_rec *s)
450 {
451 server_config_t *sconf;
452
453 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
454 "mod_arm: Entering arm_create_server_config()");
455
456 sconf = (server_config_t *) apr_pcalloc(p, sizeof(*sconf));
457 sconf->libname = DEFAULT_ARM4_LIBRARY_NAME;
458 sconf->tran_name = DEFAULT_TRAN_NAME;
459 sconf->app_name = DEFAULT_APP_NAME;
460 return sconf;
461 }
462
463 /* Create the per-dir config
464 */
465 static void *arm_create_dir_config(apr_pool_t *p, char *s)
466 {
467 dir_config_t *dconf = apr_pcalloc(p, sizeof (dir_config_t));
468 dconf->instrument_handler = 0;
469 return dconf;
470 }
471 static void *arm_merge_dir_config(apr_pool_t *p, void *basev, void *addv)
472 {
473 dir_config_t *base = (dir_config_t*) basev;
474 dir_config_t *add = (dir_config_t*) addv;
475 dir_config_t *new = apr_pcalloc(p, sizeof(dir_config_t));
476
477 new->instrument_handler = add->instrument_handler;
478 return new;
479 }
480
481 /*
482 * This function is a request pool cleanup to notify the ARM agent
483 * the transaction has ended.
484 */
485 static apr_status_t stop_transaction(void *arg)
486 {
487 request_rec *r = (request_rec *) arg;
488 arm_error_t arm_rc;
489 arm_tran_status_t tran_status;
490 request_config_t *rconf;
491
492 #if 0
493 /* This check was needed when this code was called during the
494 * logging phase. Leave in for documentation.
495 */
496 if (module_is_disabled) {
497 return DECLINED;
498 }
499 #endif
500
501 rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
502
503 if (r->status >= 500) {
504 tran_status = ARM_STATUS_ABORTED; /* Server errors */
505 }
506 else if (r->status >= 400) {
507 tran_status = ARM_STATUS_FAILED; /* Client Errors */
508 }
509 else {
510 tran_status = ARM_STATUS_GOOD; /* No Error */
511 }
512
513 arm_rc = ap_arm_stop_transaction(rconf->tran_handle,
514 tran_status,
515 0,
516 NULL);
517
518 if (arm_rc < 0) {
519 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
520 "mod_arm4: arm_stop_transaction() failed with rc: %x "
521 "Start handle: %"APR_UINT64_T_HEX_FMT"", arm_rc, rconf->tran_handle);
522 }
523 else {
524 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
525 "mod_arm4: arm_stop_transaction() handle: %"APR_UINT64_T_HEX_FMT", rc: %x",
526 rconf->tran_handle, arm_rc);
527 }
528 return APR_SUCCESS;
529 }
530
531 /* Record the HTTP request arrival time for use in the arm_start_transaction()
532 * call made after all access/auth checks have been made
533 */
534 static int arm_post_read_request(request_rec *r)
535 {
536 request_config_t *rconf;
537
538 if (module_is_disabled) {
539 return DECLINED;
540 }
541
542 /* Set up the per-request config structure */
543 rconf = apr_pcalloc(r->pool, sizeof(*rconf));
544 rconf->sb_arrival_time.header.format = ARM_SUBBUFFER_ARRIVAL_TIME;
545 ap_arm_get_arrival_time(&(rconf->sb_arrival_time.opaque_time));
546
547 ap_set_module_config(r->request_config, &arm4_module, rconf);
548
549 return DECLINED;
550 }
551
552 /* ArmLoadLibrary <library name>
553 */
554 static const char *arm_load_library(cmd_parms *parms,
555 void *dummy,
556 const char *arg)
557 {
558 server_config_t *sconf;
559 char *libname;
560 const char *c;
561
562 sconf = ap_get_module_config(parms->server->module_config, &arm4_module);
563 if (!arg) {
564 return "ArmLoadLibrary requires an ARM library name as an argument";
565 }
566 libname = apr_pstrdup(parms->pool, arg);
567
568 c = strrchr(arg, '.');
569 #ifdef _AIX
570 /* AIX presents it's shared objects in an archive file. Tweak the libname
571 * argument appropriately
572 */
573 if (c && !strcasecmp(c, ".a")) {
574 #ifdef __64BIT__
575 libname = apr_pstrcat(parms->pool, arg, "(shr_64.o)", NULL);
576 #else
577 libname = apr_pstrcat(parms->pool, arg, "(shr.o)", NULL);
578 #endif
579 }
580 #endif
581
582 sconf->libname = libname;
583 return NULL;
584 }
585
586 /* ArmTransactionName <name>
587 */
588 static const char *arm_set_transaction_name(cmd_parms *parms, void *d, const char *arg)
589 {
590 server_config_t *sconf = ap_get_module_config(parms->server->module_config, &arm4_module);
591 sconf->tran_name = apr_pstrdup(parms->pool, arg);
592 return NULL;
593 }
594
595 /* ArmApplicationName <name>
596 */
597 static const char *arm_set_application_name(cmd_parms *parms, void *d, const char *arg)
598 {
599 server_config_t *sconf = ap_get_module_config(parms->server->module_config, &arm4_module);
600 sconf->app_name = apr_pstrdup(parms->pool, arg);
601 return NULL;
602 }
603
604 /* ArmInstrumentHandler on|off
605 */
606 static const char *arm_instrument_handler(cmd_parms *parms, void *dconfv, const char *arg)
607 {
608 dir_config_t *dconf = (dir_config_t *) dconfv;
609
610 if (!strcasecmp(arg, "on")) {
611 dconf->instrument_handler = 1;
612 }
613 else {
614 dconf->instrument_handler = 0;
615 }
616 return NULL;
617 }
618
619 static const command_rec arm_commands[] = {
620 AP_INIT_TAKE1("ArmLoadLibrary", arm_load_library, NULL, RSRC_CONF | EXEC_ON_READ,
621 "the name of the ARM4 agent shared library."),
622 AP_INIT_TAKE1("ArmTransactionName", arm_set_transaction_name, NULL, RSRC_CONF,
623 "the transaction name registered with the ARM agent. Default: HTTP Request"),
624 AP_INIT_TAKE1("ArmApplicationName", arm_set_application_name, NULL, RSRC_CONF,
625 "the application name registered with the the ARM agent. Default: Apache HTTP Server"),
626 AP_INIT_TAKE1("ArmInstrumentHandler", arm_instrument_handler, NULL, RSRC_CONF | ACCESS_CONF,
627 "on|off. ArmInstrumentHandler on causes arm_block|unblock_transaction to be called across content handlers. Default: off"),
628 { NULL }
629 };
630 void arm_ap_unblock_transaction(const void *vr)
631 {
632 arm_error_t arm_rc;
633 request_config_t *rconf;
634 request_rec *r = (request_rec *) vr;
635
636 if (module_is_disabled) {
637 return;
638 }
639
640 rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
641 if (!rconf) {
642 /* We can hit this case while processing a subrequest. Checking for rconf
643 * NULL is faster check than checking for subrequest
644 */
645 return;
646 }
647 arm_rc = ap_arm_unblock_transaction(rconf->tran_handle, rconf->block_handle, 0, NULL);
648
649 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
650 "mod_arm4: arm_unblocked_transaction() handle: %"APR_UINT64_T_HEX_FMT", "
651 "block_handle: %"APR_UINT64_T_HEX_FMT", rc: %x",
652 rconf->tran_handle, rconf->block_handle, arm_rc);
653
654 return;
655 }
656
657 /*
658 * Begin definition of optional functions. These functions are used to enable a module to
659 * interface to the ARM client w/o needing to be responsible for making sure the ARM client
660 * library is loaded, initialized, etc.
661 */
662 void arm_ap_block_transaction(const void *vr)
663 {
664 arm_error_t arm_rc;
665 request_rec *r = (request_rec*) vr;
666 request_config_t *rconf;
667 /* arm_tran_block_handle_t *block_handle = apr_pcalloc(r->pool, sizeof(arm_tran_block_handle_t)); */
668
669 if (module_is_disabled) {
670 return;
671 }
672 rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
673 if (!rconf) {
674 /* We can hit this case while processing a subrequest. Checking for rconf
675 * NULL is faster check than checking for subrequest
676 */
677 return;
678 }
679
680 arm_rc = ap_arm_block_transaction(rconf->tran_handle, 0, NULL, &rconf->block_handle);
681 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
682 "mod_arm4: arm_block_transaction() handle: %"APR_UINT64_T_HEX_FMT", "
683 "block_handle: %"APR_UINT64_T_HEX_FMT", rc: %x",
684 rconf->tran_handle, rconf->block_handle, arm_rc);
685 return;
686 }
687
688 #ifdef USE_CAP_ARM_APPLICATION
689 /*
690 * Some ARM agents (on AIX) authorize users to ARM 4 interfaces thru
691 * Posix capabilities. For those systems, identify this application as
692 * an ARM Application and propagate the capabilities to the child
693 * processes.
694 */
695 static void set_process_capability(server_rec *s)
696 {
697 cap_t mycap;
698 cap_flag_value_t capflag;
699 int cap_array[2];
700
701 /*
702 * Test if the CAP_ARM_APPLICATION can be set on this version
703 * of the operating system. First, get the process' current
704 * capabilities.
705 */
706 mycap = (cap_t) cap_get_proc();
707 if (!mycap) {
708 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
709 "mod_arm: cap_get_proc failed.");
710 return;
711 }
712
713 if (cap_get_flag(mycap, CAP_ARM_APPLICATION, CAP_EFFECTIVE, &capflag)) {
714 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
715 "mod_arm: cap_get_flag failed. This OS does not support "
716 "CAP_ARM_APPLICATION.");
717 goto exit;
718 }
719
720 /*
721 * Add CAP_ARM_APPLICATION capability to current process.
722 * Always set CAP_PROPAGATE capability. Don't let errors
723 * prevent the server from starting.
724 */
725 cap_array[0] = CAP_PROPAGATE;
726 cap_array[1] = CAP_ARM_APPLICATION;
727
728 if (cap_set_flag(mycap, CAP_EFFECTIVE, 2, cap_array, CAP_SET)) {
729 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
730 "mod_arm: CAP_EFFECTIVE failed.");
731 }
732
733 if (cap_set_flag(mycap, CAP_INHERITABLE, 2, cap_array, CAP_SET)) {
734 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
735 "mod_arm: CAP_INHERITABLE failed.");
736 }
737
738 if (cap_set_flag(mycap, CAP_PERMITTED, 2, cap_array, CAP_SET)) {
739 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
740 "mod_arm: CAP_PERMITTED failed.");
741 }
742
743 /* Set the process's capabilities, you must be root to do this */
744 if (cap_set_proc(mycap)) {
745 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
746 "mod_arm: cap_set_proc() call failed.");
747 }
748
749 exit:
750 /* Free the capability allocated by cap_get_proc() */
751 cap_free(mycap);
752
753 return;
754 }
755 #endif
756
757 static int arm_post_config(apr_pool_t *p,
758 apr_pool_t *plog,
759 apr_pool_t *ptemp,
760 server_rec *s)
761 {
762 #ifdef USE_CAP_ARM_APPLICATION
763 set_process_capability(s);
764 #endif
765 return OK;
766 }
767
768 /* arm_fixups:
769 * Call arm_start_transaction() in this hook rather than in post_read_request
770 * because RemoteUser is not known until after access/auth checks have been
771 * run.
772 */
773 static int arm_fixups(request_rec *r)
774 {
775 dir_config_t *dconf;
776 server_config_t *sconf;
777 request_config_t *rconf;
778 arm_error_t arm_rc;
779 apr_uri_t uri_parts;
780
781 unsigned char *stringified_correlator;
782 const char *stringified_parent_correlator;
783 arm_correlator_t *correlator;
784 arm_correlator_t *parent_correlator;
785
786 const arm_char_t *attribvalues[9];
787 arm_buffer4_t cvbuf;
788 arm_subbuffer_t *subbuf[2];
789 arm_subbuffer_tran_context_t *sb_tran_values;
790
791 if (module_is_disabled) {
792 return DECLINED;
793 }
794
795 /* Start the request only the first time we see it. If we see it again
796 * after alias or redirect we don't want to start another one. If you'd
797 * rather do classification on the aliased or redirected URL you'll have
798 * to change this.
799 */
800 if (!ap_is_initial_req(r)) {
801 return DECLINED;
802 }
803 sconf = ap_get_module_config(r->server->module_config, &arm4_module);
804
805 rconf = (request_config_t *) ap_get_module_config(r->request_config, &arm4_module);
806 if (!rconf) {
807 /* We can hit this case while processing a subrequest. Checking for rconf
808 * NULL is faster check than checking for subrequest
809 */
810 return DECLINED;
811 }
812
813 /* Initialize the arm_subbuffer_tran_context_t
814 */
815 apr_uri_parse(r->pool, ap_construct_url(r->pool,r->uri,r), &uri_parts);
816 attribvalues[0] = apr_pstrdup(r->pool, ap_get_server_version());
817 attribvalues[1] = uri_parts.hostinfo;
818 attribvalues[2] = r->connection->remote_ip;
819 attribvalues[3] = r->user;
820 attribvalues[4] = uri_parts.scheme;
821 attribvalues[5] = apr_psprintf(r->pool, "%u", ap_get_server_port(r));
822 attribvalues[6] = apr_pstrdup(r->pool, r->args); /* Query string */
823 attribvalues[7] = "HTTP 1.1"; /* Protocol */
824 attribvalues[8] = ap_get_server_name(r);
825
826 sb_tran_values = apr_pcalloc(r->pool, sizeof(*sb_tran_values));
827 sb_tran_values->header.format = ARM_SUBBUFFER_TRAN_CONTEXT;
828 sb_tran_values->context_value_count = 9;
829 sb_tran_values->context_value_array = &attribvalues[0];
830 sb_tran_values->uri = r->uri;
831 subbuf[0] = (arm_subbuffer_t *) sb_tran_values;
832
833 /* arm_subbuffer_arrival_time_t was initialized in the post_read_request hook
834 */
835 subbuf[1] = (arm_subbuffer_t *) &rconf->sb_arrival_time;
836
837 cvbuf.count = 2;
838 cvbuf.subbuffer_array = &subbuf[0];
839
840 correlator = (arm_correlator_t *) apr_pcalloc(r->pool, ARM_CORR_MAX_LENGTH);
841
842 /* Check for an ARM_CORRELATOR header field on the inbound request, set the
843 * parent_correlator.
844 */
845 parent_correlator = NULL;
846 stringified_parent_correlator = apr_table_get(r->headers_in, "ARM_CORRELATOR");
847 if (stringified_parent_correlator) {
848 int len;
849
850 /* Do some simple validity checks on the correlator string. Ignore invalid
851 * correlators.
852 */
853 len = strlen(stringified_parent_correlator);
854 if (len > 2*ARM_CORR_MAX_LENGTH) {
855 /* Length error: exceeded max len */
856 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
857 "mod_arm: Inbound ARM_CORRELATOR failed length check. Length is %d. Correlator: %s ...",
858 len, apr_pstrndup(r->pool, stringified_parent_correlator, 20));
859 }
860 else if (len % 2) {
861 /* Length error: odd length */
862 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
863 "mod_arm: Inbound ARM_CORRELATOR failed length check. Correlator contains odd number of characters. Correlator: %s ...",
864 apr_pstrndup(r->pool, stringified_parent_correlator, 20));
865 }
866 else {
867 len = (len/2);
868 parent_correlator = (arm_correlator_t *) apr_pcalloc(r->pool, ARM_CORR_MAX_LENGTH);
869 destringify((const unsigned char*)stringified_parent_correlator, (unsigned char*) parent_correlator, len);
870 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
871 "mod_arm: Received ARM_CORRELATOR header field. Correlator: %s ...",
872 apr_pstrndup(r->pool, stringified_parent_correlator, 20));
873 }
874 }
875
876 /* ARM_FLAG_BIND_THREAD is only valid if the same thread calls
877 * arm_start_transaction() and arm_stop_transaction(). This assumption
878 * breaks when httpd supports non-blocking event driven or async
879 * i/o.
880 */
881 arm_rc = ap_arm_start_transaction(sconf->app_handle,
882 &(sconf->tran_id),
883 parent_correlator,
884 ARM_FLAG_BIND_THREAD,
885 &cvbuf,
886 &rconf->tran_handle,
887 correlator);
888 if (arm_rc < 0) {
889 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
890 "mod_arm: arm_start_transaction() failed with rc = %x", arm_rc);
891 }
892 else {
893 /* Register the stop_transaction only if the call to
894 * start_transaction is successful.
895 */
896 apr_pool_cleanup_register(r->pool, r, stop_transaction,
897 apr_pool_cleanup_null);
898 stringified_correlator = (unsigned char *) apr_pcalloc(r->pool, (2*ARM_CORR_MAX_LENGTH+1));
899 stringify_Correlator(correlator, stringified_correlator);
900 }
901
902 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
903 "mod_arm4: arm_start_transaction() handle: %"APR_UINT64_T_HEX_FMT", rc: %x\n"
904 "\tcorrelator: %s\n"
905 "\tconstructed url: %s\n"
906 "\tattr::ServerVersion: %s\n"
907 "\tattr::Hostinfo: %s\n"
908 "\tattr::RemoteAddress: %s\n"
909 "\tattr::RemoteUser: %s\n"
910 "\tattr::Scheme: %s\n"
911 "\tattr::Port: %s\n"
912 "\tattr::QueryString: %s\n"
913 "\tattr::Protocol: %s\n"
914 "\tattr::ServerName: %s\n",
915 rconf->tran_handle, arm_rc,
916 stringified_correlator,
917 ap_construct_url(r->pool, r->uri, r),
918 attribvalues[0],
919 attribvalues[1],
920 attribvalues[2],
921 attribvalues[3],
922 attribvalues[4],
923 attribvalues[5],
924 attribvalues[6],
925 attribvalues[7],
926 attribvalues[8]);
927
928 /* TODO: Develop config driven or huristic for when to add the ARM_CORRELATOR.
929 * For now, always add the correlator.
930 */
931 apr_table_set(r->headers_in, "ARM_CORRELATOR", (char*) stringified_correlator);
932 apr_table_set(r->err_headers_out, "ARM_CORRELATOR", (char*) stringified_correlator); /* Is this necessary? */
933
934 /* Poor man's way to bracket the call to the handler with
935 * arm_block_transaction()/arm_unblock_transaction() calls. The
936 * arm_unblock_transaction() is called in the logging phase. If you
937 * can live with the potential inacuracies with this method, you can
938 * eliminate the need to instrument each and every handler with block/unblock
939 * calls.
940 */
941 dconf = (dir_config_t *) ap_get_module_config(r->per_dir_config, &arm4_module);
942 if (dconf->instrument_handler) {
943 arm_ap_block_transaction(r);
944 }
945 return DECLINED;
946 }
947
948 /* arm_logger(): poor man's arm_unblock_tranaction()
949 * TODO: Consider implementing this call in a simple output filter that
950 * sets high in the stack.
951 */
952 static int arm_logger(request_rec *r)
953 {
954 dir_config_t *dconf;
955
956 if (module_is_disabled) {
957 return DECLINED;
958 }
959 dconf = (dir_config_t *) ap_get_module_config(r->per_dir_config, &arm4_module);
960 if (dconf->instrument_handler) {
961 arm_ap_unblock_transaction(r);
962 }
963 return DECLINED;
964 }
965
966
967 static void arm_register_hooks(apr_pool_t *p)
968 {
969 ap_hook_post_config(arm_post_config, NULL, NULL, APR_HOOK_MIDDLE);
970 ap_hook_fixups(arm_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST);
971 ap_hook_log_transaction(arm_logger, NULL, NULL, APR_HOOK_LAST);
972 ap_hook_post_read_request(arm_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
973 ap_hook_child_init(arm_child_init, NULL, NULL, APR_HOOK_MIDDLE);
974 APR_REGISTER_OPTIONAL_FN(arm_ap_block_transaction);
975 APR_REGISTER_OPTIONAL_FN(arm_ap_unblock_transaction);
976 }
977
978 module AP_MODULE_DECLARE_DATA ARM_MODULE =
979 {
980 STANDARD20_MODULE_STUFF,
981 arm_create_dir_config, /* per-directory config creator */
982 arm_merge_dir_config, /* dir config merger */
983 arm_create_server_config, /* server config creator */
984 NULL, /* server config merger */
985 arm_commands, /* command table */
986 arm_register_hooks, /* register hooks*/
987 };

Properties

Name Value
svn:eol-style native

infrastructure at apache.org
ViewVC Help
Powered by ViewVC 1.1.26