1 /* $OpenBSD: ap_hook.h,v 1.5 2005/03/28 23:26:51 niallo Exp $ */ 2 3 #if 0 4 =cut 5 #endif 6 /* ==================================================================== 7 * Copyright (c) 1998-2000 The Apache Group. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the Apache Group 24 * for use in the Apache HTTP server project (http://www.apache.org/)." 25 * 26 * 4. The names "Apache Server" and "Apache Group" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache" 32 * nor may "Apache" appear in their names without prior written 33 * permission of the Apache Group. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the Apache Group 38 * for use in the Apache HTTP server project (http://www.apache.org/)." 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This software consists of voluntary contributions made by many 55 * individuals on behalf of the Apache Group and was originally based 56 * on public domain software written at the National Center for 57 * Supercomputing Applications, University of Illinois, Urbana-Champaign. 58 * For more information on the Apache Group and the Apache HTTP server 59 * project, please see <http://www.apache.org/>. 60 * 61 */ 62 63 /* 64 ** Implementation of a Generic Hook Interface for Apache 65 ** Written by Ralf S. Engelschall <rse@engelschall.com> 66 ** 67 ** See POD document at end of this file for description. 68 ** View it with the command ``pod2man ap_hook.h | nroff -man | more'' 69 ** 70 ** Attention: This header file is a little bit tricky. 71 ** It's a combination of a C source and an embedded POD document 72 ** The purpose of this is to have both things together at one 73 ** place. So you can both pass this file to the C compiler and 74 ** the pod2man translater. 75 */ 76 77 #ifndef AP_HOOK_H 78 #define AP_HOOK_H 79 80 /* 81 * Function Signature Specification: 82 * 83 * We encode the complete signature ingredients as a bitfield 84 * stored in a single unsigned long integer value, which can be 85 * constructed with AP_HOOK_SIGx(...) 86 */ 87 88 /* the type of the signature bitfield */ 89 typedef unsigned long int ap_hook_sig; 90 91 /* the mask (bin) 111 (hex 0x7) for the triples in the bitfield */ 92 #define AP_HOOK_SIG_TRIPLE_MASK 0x7 93 94 /* the position of the triple */ 95 #define AP_HOOK_SIG_TRIPLE_POS(n) ((n)*3) 96 97 /* the constructor for triple #n with value v */ 98 #define AP_HOOK_SIG_TRIPLE(n,v) \ 99 (((ap_hook_sig)(v))<<((AP_HOOK_##n)*3)) 100 101 /* the check whether triple #n in sig contains value v */ 102 #define AP_HOOK_SIG_HAS(sig,n,v) \ 103 ((((ap_hook_sig)(sig))&AP_HOOK_SIG_TRIPLE(n, AP_HOOK_SIG_TRIPLE_MASK)) == (AP_HOOK_##n##_##v)) 104 105 /* utility function to get triple #n in sig */ 106 #define AP_HOOK_SIG_TRIPLE_GET(sig,n) \ 107 ((((ap_hook_sig)(sig))>>AP_HOOK_SIG_TRIPLE_POS(n))&(AP_HOOK_SIG_TRIPLE_MASK)) 108 109 /* utility function to set triple #n in sig to value v */ 110 #define AP_HOOK_SIG_TRIPLE_SET(sig,n,v) \ 111 ((((ap_hook_sig)(sig))&~(AP_HOOK_SIG_TRIPLE_MASK<<AP_HOOK_SIG_TRIPLE_POS(n)))|((v)<<AP_HOOK_SIG_TRIPLE_POS(n))) 112 113 /* define the ingredients for the triple #0: id stuff */ 114 #define AP_HOOK_ID 0 115 #define AP_HOOK_ID_ok AP_HOOK_SIG_TRIPLE(ID,0) 116 #define AP_HOOK_ID_undef AP_HOOK_SIG_TRIPLE(ID,1) 117 118 /* define the ingredients for the triple #1: return code */ 119 #define AP_HOOK_RC 1 120 #define AP_HOOK_RC_void AP_HOOK_SIG_TRIPLE(RC,0) 121 #define AP_HOOK_RC_char AP_HOOK_SIG_TRIPLE(RC,1) 122 #define AP_HOOK_RC_int AP_HOOK_SIG_TRIPLE(RC,2) 123 #define AP_HOOK_RC_long AP_HOOK_SIG_TRIPLE(RC,3) 124 #define AP_HOOK_RC_float AP_HOOK_SIG_TRIPLE(RC,4) 125 #define AP_HOOK_RC_double AP_HOOK_SIG_TRIPLE(RC,5) 126 #define AP_HOOK_RC_ptr AP_HOOK_SIG_TRIPLE(RC,6) 127 128 /* define the ingredients for the triple #2: argument 1 */ 129 #define AP_HOOK_A1 2 130 #define AP_HOOK_A1_ctx AP_HOOK_SIG_TRIPLE(A1,0) 131 #define AP_HOOK_A1_char AP_HOOK_SIG_TRIPLE(A1,1) 132 #define AP_HOOK_A1_int AP_HOOK_SIG_TRIPLE(A1,2) 133 #define AP_HOOK_A1_long AP_HOOK_SIG_TRIPLE(A1,3) 134 #define AP_HOOK_A1_float AP_HOOK_SIG_TRIPLE(A1,4) 135 #define AP_HOOK_A1_double AP_HOOK_SIG_TRIPLE(A1,5) 136 #define AP_HOOK_A1_ptr AP_HOOK_SIG_TRIPLE(A1,6) 137 138 /* define the ingredients for the triple #3: argument 2 */ 139 #define AP_HOOK_A2 3 140 #define AP_HOOK_A2_ctx AP_HOOK_SIG_TRIPLE(A2,0) 141 #define AP_HOOK_A2_char AP_HOOK_SIG_TRIPLE(A2,1) 142 #define AP_HOOK_A2_int AP_HOOK_SIG_TRIPLE(A2,2) 143 #define AP_HOOK_A2_long AP_HOOK_SIG_TRIPLE(A2,3) 144 #define AP_HOOK_A2_float AP_HOOK_SIG_TRIPLE(A2,4) 145 #define AP_HOOK_A2_double AP_HOOK_SIG_TRIPLE(A2,5) 146 #define AP_HOOK_A2_ptr AP_HOOK_SIG_TRIPLE(A2,6) 147 148 /* define the ingredients for the triple #4: argument 3 */ 149 #define AP_HOOK_A3 4 150 #define AP_HOOK_A3_ctx AP_HOOK_SIG_TRIPLE(A3,0) 151 #define AP_HOOK_A3_char AP_HOOK_SIG_TRIPLE(A3,1) 152 #define AP_HOOK_A3_int AP_HOOK_SIG_TRIPLE(A3,2) 153 #define AP_HOOK_A3_long AP_HOOK_SIG_TRIPLE(A3,3) 154 #define AP_HOOK_A3_float AP_HOOK_SIG_TRIPLE(A3,4) 155 #define AP_HOOK_A3_double AP_HOOK_SIG_TRIPLE(A3,5) 156 #define AP_HOOK_A3_ptr AP_HOOK_SIG_TRIPLE(A3,6) 157 158 /* define the ingredients for the triple #5: argument 4 */ 159 #define AP_HOOK_A4 5 160 #define AP_HOOK_A4_ctx AP_HOOK_SIG_TRIPLE(A4,0) 161 #define AP_HOOK_A4_char AP_HOOK_SIG_TRIPLE(A4,1) 162 #define AP_HOOK_A4_int AP_HOOK_SIG_TRIPLE(A4,2) 163 #define AP_HOOK_A4_long AP_HOOK_SIG_TRIPLE(A4,3) 164 #define AP_HOOK_A4_float AP_HOOK_SIG_TRIPLE(A4,4) 165 #define AP_HOOK_A4_double AP_HOOK_SIG_TRIPLE(A4,5) 166 #define AP_HOOK_A4_ptr AP_HOOK_SIG_TRIPLE(A4,6) 167 168 /* define the ingredients for the triple #6: argument 5 */ 169 #define AP_HOOK_A5 6 170 #define AP_HOOK_A5_ctx AP_HOOK_SIG_TRIPLE(A5,0) 171 #define AP_HOOK_A5_char AP_HOOK_SIG_TRIPLE(A5,1) 172 #define AP_HOOK_A5_int AP_HOOK_SIG_TRIPLE(A5,2) 173 #define AP_HOOK_A5_long AP_HOOK_SIG_TRIPLE(A5,3) 174 #define AP_HOOK_A5_float AP_HOOK_SIG_TRIPLE(A5,4) 175 #define AP_HOOK_A5_double AP_HOOK_SIG_TRIPLE(A5,5) 176 #define AP_HOOK_A5_ptr AP_HOOK_SIG_TRIPLE(A5,6) 177 178 /* define the ingredients for the triple #7: argument 6 */ 179 #define AP_HOOK_A6 7 180 #define AP_HOOK_A6_ctx AP_HOOK_SIG_TRIPLE(A6,0) 181 #define AP_HOOK_A6_char AP_HOOK_SIG_TRIPLE(A6,1) 182 #define AP_HOOK_A6_int AP_HOOK_SIG_TRIPLE(A6,2) 183 #define AP_HOOK_A6_long AP_HOOK_SIG_TRIPLE(A6,3) 184 #define AP_HOOK_A6_float AP_HOOK_SIG_TRIPLE(A6,4) 185 #define AP_HOOK_A6_double AP_HOOK_SIG_TRIPLE(A6,5) 186 #define AP_HOOK_A6_ptr AP_HOOK_SIG_TRIPLE(A6,6) 187 188 /* define the ingredients for the triple #8: argument 7 */ 189 #define AP_HOOK_A7 8 190 #define AP_HOOK_A7_ctx AP_HOOK_SIG_TRIPLE(A7,0) 191 #define AP_HOOK_A7_char AP_HOOK_SIG_TRIPLE(A7,1) 192 #define AP_HOOK_A7_int AP_HOOK_SIG_TRIPLE(A7,2) 193 #define AP_HOOK_A7_long AP_HOOK_SIG_TRIPLE(A7,3) 194 #define AP_HOOK_A7_float AP_HOOK_SIG_TRIPLE(A7,4) 195 #define AP_HOOK_A7_double AP_HOOK_SIG_TRIPLE(A7,5) 196 #define AP_HOOK_A7_ptr AP_HOOK_SIG_TRIPLE(A7,6) 197 198 /* define the ingredients for the triple #9: argument 8 */ 199 #define AP_HOOK_A8 9 200 #define AP_HOOK_A8_ctx AP_HOOK_SIG_TRIPLE(9,0) 201 #define AP_HOOK_A8_char AP_HOOK_SIG_TRIPLE(9,1) 202 #define AP_HOOK_A8_int AP_HOOK_SIG_TRIPLE(9,2) 203 #define AP_HOOK_A8_long AP_HOOK_SIG_TRIPLE(9,3) 204 #define AP_HOOK_A8_float AP_HOOK_SIG_TRIPLE(9,4) 205 #define AP_HOOK_A8_double AP_HOOK_SIG_TRIPLE(9,5) 206 #define AP_HOOK_A8_ptr AP_HOOK_SIG_TRIPLE(9,6) 207 208 /* the constructor for unknown signatures */ 209 #define AP_HOOK_SIG_UNKNOWN AP_HOOK_ID_undef 210 211 /* the constructor for signatures with 1 type */ 212 #define AP_HOOK_SIG1(rc) \ 213 (AP_HOOK_RC_##rc) 214 215 /* the constructor for signatures with 2 types */ 216 #define AP_HOOK_SIG2(rc,a1) \ 217 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1) 218 219 /* the constructor for signatures with 3 types */ 220 #define AP_HOOK_SIG3(rc,a1,a2) \ 221 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1|AP_HOOK_A2_##a2) 222 223 /* the constructor for signatures with 4 types */ 224 #define AP_HOOK_SIG4(rc,a1,a2,a3) \ 225 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1|AP_HOOK_A2_##a2|AP_HOOK_A3_##a3) 226 227 /* the constructor for signatures with 5 types */ 228 #define AP_HOOK_SIG5(rc,a1,a2,a3,a4) \ 229 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1|AP_HOOK_A2_##a2|AP_HOOK_A3_##a3|AP_HOOK_A4_##a4) 230 231 /* the constructor for signatures with 6 types */ 232 #define AP_HOOK_SIG6(rc,a1,a2,a3,a4,a5) \ 233 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1|AP_HOOK_A2_##a2|AP_HOOK_A3_##a3|AP_HOOK_A4_##a4|AP_HOOK_A5_##a5) 234 235 /* the constructor for signatures with 7 types */ 236 #define AP_HOOK_SIG7(rc,a1,a2,a3,a4,a5,a6) \ 237 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1|AP_HOOK_A2_##a2|AP_HOOK_A3_##a3|AP_HOOK_A4_##a4|AP_HOOK_A5_##a5|AP_HOOK_A6_##a6) 238 239 /* the constructor for signatures with 8 types */ 240 #define AP_HOOK_SIG8(rc,a1,a2,a3,a4,a5,a6,a7) \ 241 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1|AP_HOOK_A2_##a2|AP_HOOK_A3_##a3|AP_HOOK_A4_##a4|AP_HOOK_A5_##a5|AP_HOOK_A6_##a6|AP_HOOK_A7_##a7) 242 243 /* the constructor for signatures with 9 types */ 244 #define AP_HOOK_SIG9(rc,a1,a2,a3,a4,a5,a6,a7,a8) \ 245 (AP_HOOK_RC_##rc|AP_HOOK_A1_##a1|AP_HOOK_A2_##a2|AP_HOOK_A3_##a3|AP_HOOK_A4_##a4|AP_HOOK_A5_##a5|AP_HOOK_A6_##a6|AP_HOOK_A7_##a7|AP_HOOK_A8_##a8) 246 247 /* 248 * Return Value Mode Identification 249 */ 250 251 /* the type of the return value modes */ 252 typedef unsigned int ap_hook_mode; 253 254 /* the mode of the return value */ 255 #define AP_HOOK_MODE_UNKNOWN 0 256 #define AP_HOOK_MODE_TOPMOST 1 257 #define AP_HOOK_MODE_DECLINE 2 258 #define AP_HOOK_MODE_DECLTMP 3 259 #define AP_HOOK_MODE_ALL 4 260 261 /* the constructors for the return value modes */ 262 #define AP_HOOK_TOPMOST AP_HOOK_MODE_TOPMOST 263 #define AP_HOOK_DECLINE(val) AP_HOOK_MODE_DECLINE, (val) 264 #define AP_HOOK_DECLTMP(val) AP_HOOK_MODE_DECLTMP, (val) 265 #define AP_HOOK_ALL AP_HOOK_MODE_ALL 266 267 /* 268 * Hook State Identification 269 */ 270 271 /* the type of the hook state */ 272 typedef unsigned short int ap_hook_state; 273 274 /* the values of the hook state */ 275 #define AP_HOOK_STATE_UNDEF 0 276 #define AP_HOOK_STATE_NOTEXISTANT 1 277 #define AP_HOOK_STATE_ESTABLISHED 2 278 #define AP_HOOK_STATE_CONFIGURED 3 279 #define AP_HOOK_STATE_REGISTERED 4 280 281 /* 282 * Hook Context Identification 283 * 284 * Notice: Null is ok here, because AP_HOOK_NOCTX is just a dummy argument 285 * because we know from the signature whether the argument is a 286 * context value or just the dummy value. 287 */ 288 289 #define AP_HOOK_NOCTX (void *)(0) 290 #define AP_HOOK_CTX(v) (void *)(v) 291 292 /* 293 * Internal Hook Record Definition 294 */ 295 296 /* the union holding the arbitrary decline values */ 297 typedef union { 298 char v_char; 299 int v_int; 300 long v_long; 301 float v_float; 302 double v_double; 303 void *v_ptr; 304 } ap_hook_value; 305 306 /* the structure holding one hook function and its context */ 307 typedef struct { 308 void *hf_ptr; /* function pointer */ 309 void *hf_ctx; /* function context */ 310 } ap_hook_func; 311 312 /* the structure holding one hook entry with all its registered functions */ 313 typedef struct { 314 char *he_hook; /* hook name (=unique id) */ 315 ap_hook_sig he_sig; /* hook signature */ 316 int he_modeid; /* hook mode id */ 317 ap_hook_value he_modeval; /* hook mode value */ 318 ap_hook_func **he_func; /* hook registered funcs */ 319 } ap_hook_entry; 320 321 /* the maximum number of hooks and functions per hook */ 322 #define AP_HOOK_MAX_ENTRIES 512 323 #define AP_HOOK_MAX_FUNCS 128 324 325 /* 326 * Extended Variable Argument (vararg) Support 327 * 328 * In ANSI C varargs exists, but because the prototypes of function with 329 * varargs cannot reflect the types of the varargs, K&R argument passing 330 * conventions have to apply for the compiler. This means mainly a conversion 331 * of shorter type variants to the maximum variant (according to sizeof). The 332 * above va_type() macro provides this mapping from the wanted types to the 333 * physically used ones. 334 */ 335 336 /* the mapping */ 337 #define VA_TYPE_char int 338 #define VA_TYPE_short int 339 #define VA_TYPE_int int 340 #define VA_TYPE_long long 341 #define VA_TYPE_float double 342 #define VA_TYPE_double double 343 #define VA_TYPE_ptr void * 344 #define VA_TYPE_ctx void * 345 346 /* the constructor */ 347 #ifdef va_type 348 #undef va_type 349 #endif 350 #define va_type(type) VA_TYPE_ ## type 351 352 /* 353 * Miscellaneous stuff 354 */ 355 356 #ifndef FALSE 357 #define FALSE 0 358 #define TRUE !FALSE 359 #endif 360 361 /* 362 * Wrapper macros for the callback-function register/unregister calls. 363 * 364 * Background: Strict ANSI C doesn't allow a function pointer to be treated as 365 * a void pointer on argument passing, but we cannot declare the argument as a 366 * function prototype, because the functions can have arbitrary signatures. So 367 * we have to use a void pointer here. But to not require explicit casts on 368 * function pointers for every register/unregister call, we smooth the API a 369 * little bit by providing these macros. 370 */ 371 372 #define ap_hook_register(hook,func,ctx) ap_hook_register_I(hook,(void *)(func),ctx) 373 #define ap_hook_unregister(hook,func) ap_hook_unregister_I(hook,(void *)(func)) 374 375 /* 376 * Prototypes for the hook API functions 377 */ 378 379 API_EXPORT(void) ap_hook_init (void); 380 API_EXPORT(void) ap_hook_kill (void); 381 API_EXPORT(int) ap_hook_configure (char *hook, ap_hook_sig sig, 382 ap_hook_mode modeid, ...); 383 API_EXPORT(int) ap_hook_register_I (char *hook, void *func, 384 void *ctx); 385 API_EXPORT(int) ap_hook_unregister_I (char *hook, void *func); 386 API_EXPORT(ap_hook_state) ap_hook_status (char *hook); 387 API_EXPORT(int) ap_hook_use (char *hook, ap_hook_sig sig, 388 ap_hook_mode modeid, ...); 389 API_EXPORT(int) ap_hook_call (char *hook, ...); 390 391 #endif /* AP_HOOK_H */ 392 393 /* 394 =pod 395 ## 396 ## Embedded POD document 397 ## 398 399 =head1 NAME 400 401 B<ap_hook> - B<Generic Hook Interface for Apache> 402 403 =head1 SYNOPSIS 404 405 B<Hook Library Setup:> 406 407 void ap_hook_init(void); 408 void ap_hook_kill(void); 409 410 B<Hook Configuration and Registration:> 411 412 int ap_hook_configure(char *hook, ap_hook_sig sig, ap_hook_mode mode); 413 int ap_hook_register(char *hook, void *func, void *ctx); 414 int ap_hook_unregister(char *hook, void *func); 415 416 B<Hook Usage:> 417 418 ap_hook_state ap_hook_status(char *hook); 419 int ap_hook_use(char *hook, ap_hook_sig sig, ap_hook_mode mode, ...); 420 int ap_hook_call(char *hook, ...); 421 422 B<Hook Signature Constructors> (ap_hook_sig): 423 424 AP_HOOK_SIG1(rc) 425 AP_HOOK_SIG2(rc,a1) 426 AP_HOOK_SIG3(rc,a1,a2) 427 AP_HOOK_SIG4(rc,a1,a2,a3) 428 AP_HOOK_SIG5(rc,a1,a2,a3,a4) 429 AP_HOOK_SIG6(rc,a1,a2,a3,a4,a5) 430 AP_HOOK_SIG7(rc,a1,a2,a3,a4,a5,a6) 431 AP_HOOK_SIG8(rc,a1,a2,a3,a4,a5,a6,a7) 432 433 B<Hook Modes Constructors> (ap_hook_mode): 434 435 AP_HOOK_TOPMOST 436 AP_HOOK_DECLINE(value) 437 AP_HOOK_DECLTMP(value) 438 AP_HOOK_ALL 439 440 B<Hook States> (ap_hook_state): 441 442 AP_HOOK_STATE_UNDEF 443 AP_HOOK_STATE_NOTEXISTANT 444 AP_HOOK_STATE_ESTABLISHED 445 AP_HOOK_STATE_CONFIGURED 446 AP_HOOK_STATE_REGISTERED 447 448 =head1 DESCRIPTION 449 450 This library implements a generic hook interface for Apache which can be used 451 to loosely couple code through arbitrary hooks. There are two use cases for 452 this mechanism: 453 454 =over 3 455 456 =item B<1. Extension and Overrides> 457 458 Inside a specific code section you want to perform a specific function call 459 for extension reasons. But you want to allow one or more modules to implement 460 this function by registering hooks. Those hooks are registered on a stack and 461 can be even configured to have a I<decline> return value. As long as there are 462 functions which return the decline value the next function on the stack is 463 tried. When the first function doesn't return the decline value the hook call 464 stops. 465 466 The original intent of this use case is to provide a flexible extension 467 mechanism where modules can override functionality. 468 469 =item B<2. Intercommunication> 470 471 Inside a specific code you have a function you want to export. But you first 472 want to allow other code to override this function. And second you want to 473 export this function without real object file symbol references. Instead you 474 want to register the function and let the users call this function by name. 475 476 The original intent of this use case is to allow inter-module communication 477 without direct symbol references, which are a big I<no-no> for the I<Dynamic 478 Shared Object> (DSO) situation. 479 480 =back 481 482 And the following design goals existed: 483 484 =over 3 485 486 =item B<1. Minimum code changes> 487 488 The hook calls should look very similar to the corresponding direct function 489 call to allow one to easily translate it. And the total amount of changes for 490 the hook registration, hook configuration and hook usage should be as small as 491 possible to minimize the total code changes. Additionally a shorthand API 492 function (ap_hook_use) should be provided which lets one trivially add a hook 493 by just changing the code at a single location. 494 495 =item B<2. The hook call has to be maximum flexible> 496 497 In order to avoid nasty hacks, maximum flexiblity for the hook calls is 498 needed, i.e. any function signature (the set of types for the return value and 499 the arguments) should be supported. And it should be possible to 500 register always a context (ctx) variable with a function which is passed to 501 the corresponding function when the hook call is performed. 502 503 =back 504 505 The implementation of this library directly followed these two design goals. 506 507 =head1 USAGE 508 509 Using this hook API is a four-step process: 510 511 =over 3 512 513 =item B<1. Initialization> 514 515 Initialize or destroy the hook mechanism inside your application program: 516 517 ap_hook_init(); 518 : 519 ap_hook_kill(); 520 521 =item B<2. Configuration> 522 523 Configure a particular hook by specifing its name, signature and return type 524 semantic: 525 526 ap_hook_configure("lookup", AP_HOOK_SIG2(ptr,ptr,ctx), AP_HOOK_DECLINE(NULL)); 527 ap_hook_configure("setup", AP_HOOK_SIG2(int,ptr,char), AP_HOOK_DECLTMP(FALSE)); 528 ap_hook_configure("read", AP_HOOK_SIG2(void,ptr), AP_HOOK_TOPMOST); 529 ap_hook_configure("logit", AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL); 530 531 This configures four hooks: 532 533 A hook named C<lookup> with the signature C<void *lookup(void *, void *)> 534 (where the second argument is C<NULL> or the private context pointer of the 535 hook function which can be optionally provided at the registration step 536 later) and a return code semantic which says: Proceed as long as the 537 registered lookup functions return C<NULL> or no more registered functions 538 exists. A call for this hook has to provide 2 argument only (a pointer to the 539 return variable and the first argument), because the context is 540 implicitly provided by the hook mechanism. Sample idea: I<The first function 541 who was successful in looking up a variable provides the value>. 542 543 A hook named C<setup> with the signature C<int setup(void *, char)" and a 544 return code semantic equal to the one of the C<lookup> hook. But the decline 545 return value is implemented by a temporay variable of the hook mechanism and 546 only used for the decline decision. So a call to this hook has to provide 2 547 arguments only (the first and second argument, but no address to a return 548 value). Sample idea: I<Any function can handle the setup and when one 549 function handled it stops the processing by indicating this with the return 550 value>. 551 552 A hook named C<read> with the signature C<void read(void *)> and a return code 553 semantic which says: Only the top most function on the registered function 554 stack is tried (and independet of a possible return value in non-void 555 context). A call to this hook has to provide exactly 1 argument (the 556 single argument to the hook function). Sample idea: I<We want to 557 use a read function and allow others to override it, but independent how much 558 registered functions exists, only top most (= last registered) function 559 overrides and is used>. 560 561 A hook named C<logit> with the signature C<void logit(void *)> and a return 562 code semantic which says: All registered functions on the hook functioin stack 563 are tried. Sample idea: I<We pass a FILE pointer to the logging functions and 564 any function can log whatever it wants>. 565 566 =item B<3. Registration> 567 568 Register the actual functions which should be used by the hook: 569 570 ap_hook_register("lookup", mylookup, mycontext); 571 ap_hook_register("setup", mysetup); 572 ap_hook_register("read", myread); 573 ap_hook_register("logit", mylogit); 574 575 This registers the function C<mylookup()> under the C<lookup> hook with the 576 private context given by the variable C<mycontext>. And it registers the 577 function C<mysetup()> under the C<setup> hook without any context. Same for 578 C<myread> and C<mylogit>. 579 580 =item B<4. Usage> 581 582 Finally use the hooks, i.e. instead of using direct function calls like 583 584 rc = mylookup(a1, a2); 585 rc = mysetup(a1, a2); 586 myread(a1); 587 mylogit(a1); 588 589 you now use: 590 591 ap_hook_call("lookup", &rc, a1, a2); 592 ap_hook_call("setup", &rc, a1, a2); 593 ap_hook_call("read", a1); 594 ap_hook_call("logit", a1); 595 596 which are internally translated to: 597 598 rc = mylookup(a1, a2, mycontext); 599 rc = mysetup(a1, a2); 600 myread(a1); 601 mylogit(a1); 602 603 Notice two things here: First the context (C<mycontext>) for the C<mylookup()> 604 function is automatically added by the hook mechanism. And it is a different 605 (and not fixed) context for each registered function, of course. Second, 606 return values always have to be pushed into variables and a pointer to them 607 has to be given as the second argument to C<ap_hook_call> (except for 608 functions which have a void return type, of course). 609 610 BTW, the return value of C<ap_hook_call()> is always C<TRUE> or C<FALSE>. 611 C<TRUE> when at least one function call was successful (always the case for 612 C<AP_HOOK_TOPMOST> and C<AP_HOOK_ALL>). C<FALSE> when all functions 613 returned the decline value or no functions are registered at all. 614 615 =back 616 617 =head1 RESTRICTIONS 618 619 To make the hook implementation efficient and to not bloat up the code too 620 much a few restrictions have to make: 621 622 =over 3 623 624 =item 1. 625 626 Only function calls with up to 4 arguments are implemented. When more are 627 needed you can either extend the hook implementation by using more bits for 628 the signature configuration or you can do a workaround when the function is 629 your own one: Put the remaining (N-4-1) arguments into a structure and pass 630 only a pointer (one argument) as the forth argument. 631 632 =item 2. 633 634 Only the following ANSI C variable types are supported: 635 636 - For the return value: 637 void (= none), char, int, float, double, ptr (= void *) 638 - For the arguments: 639 ctx (= context), char, int, float, double, ptr (= void *) 640 641 This means in theory that 6^5 (=7776) signature combinations are possible. But 642 because we don't need all of them inside Apache and it would bloat up the code 643 too dramatically we implement only a subset of those combinations. The 644 implemented signatures can be specified inside C<ap_hook.c> and the 645 corresponding code can be automatically generated by running ``C<perl 646 ap_hook.c>'' (yeah, no joke ;-). So when you need a hook with a different 647 still not implemented signature you either have to again use a workaround as 648 above (i.e. use a structure) or just add the signature to the C<ap_hook.c> 649 file. 650 651 =head1 EXAMPLE 652 653 We want to call `C<ssize_t read(int, void *, size_t)>' through hooks in order 654 to allow modules to override this call. So, somewhere we have a replacement 655 function for C<read()> defined (same signature, of course): 656 657 ssize_t my_read(int, void *, size_t); 658 659 We now configure a C<read> hook. Here the C<AP_HOOK_SIGx()> macro defines the 660 signature of the C<read()>-like callback functions and has to match the 661 prototype of C<read()>. But we have to replace typedefs with the physical 662 underlaying ANSI C types. And C<AP_HOOK_DECLINE()> sets the return value of 663 the read()-like functions which forces the next hook to be called (here -1). 664 And we register the original C<read()> function as the default hook. 665 666 ap_hook_configure("read", 667 AP_HOOK_SIG4(int,int,ptr,int), 668 AP_HOOK_DECLINE(-1)); 669 ap_hook_register("read", read); 670 671 Now a module wants to override the C<read()> call and registers the 672 C<my_read()> function: 673 674 ap_hook_register("read", my_read); 675 676 The function logically gets pushed onto a stack, so the execution order is the 677 reverse registering order, i.e. I<last registered - first called>. Now we can 678 replace the standard C<read()> call 679 680 bytes = read(fd, buf, bufsize); 681 if (bytes == -1) 682 ...error... 683 684 with the hook based call: 685 686 rc = ap_hook_call("read", &bytes, fd, buf, bufsize); 687 if (rc == FALSE) 688 ...error... 689 690 Now internally the following is done: The call `C<bytes = my_read(fd, buf, 691 bufsize)>' is done. When it returns not -1 (the decline value) nothing 692 more is done. But when C<my_read()> returns -1 the next function is tried: 693 `C<bytes = read(fd, buf, bufsize)>'. When this one also returns -1 you get 694 `rc == FALSE'. When it finally returns not -1 you get `rc == TRUE'. 695 696 =head1 SEE ALSO 697 698 ap_ctx(3) 699 700 =head1 HISTORY 701 702 The ap_hook(3) interface was originally designed and 703 implemented in October 1998 by Ralf S. Engelschall. 704 705 =head1 AUTHOR 706 707 Ralf S. Engelschall 708 rse@engelschall.com 709 www.engelschall.com 710 711 =cut 712 */ 713