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