bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / modules / metadata / mod_unique_id.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * mod_unique_id.c: generate a unique identifier for each request
19  *
20  * Original author: Dean Gaudet <dgaudet@arctic.org>
21  * UUencoding modified by: Alvaro Martinez Echevarria <alvaro@lander.es>
22  */
23
24 #define APR_WANT_BYTEFUNC   /* for htons() et al */
25 #include "apr_want.h"
26 #include "apr_general.h"    /* for APR_OFFSETOF                */
27 #include "apr_network_io.h"
28
29 #include "httpd.h"
30 #include "http_config.h"
31 #include "http_log.h"
32 #include "http_protocol.h"  /* for ap_hook_post_read_request */
33
34 #if APR_HAVE_UNISTD_H
35 #include <unistd.h>         /* for getpid() */
36 #endif
37
38 typedef struct {
39     unsigned int stamp;
40     unsigned int in_addr;
41     unsigned int pid;
42     unsigned short counter;
43     unsigned int thread_index;
44 } unique_id_rec;
45
46 /* We are using thread_index (the index into the scoreboard), because we
47  * cannot guarantee the thread_id will be an integer.
48  *
49  * This code looks like it won't give a unique ID with the new thread logic.
50  * It will.  The reason is, we don't increment the counter in a thread_safe 
51  * manner.  Because the thread_index is also in the unique ID now, this does
52  * not matter.  In order for the id to not be unique, the same thread would
53  * have to get the same counter twice in the same second. 
54  */
55
56 /* Comments:
57  *
58  * We want an identifier which is unique across all hits, everywhere.
59  * "everywhere" includes multiple httpd instances on the same machine, or on
60  * multiple machines.  Essentially "everywhere" should include all possible
61  * httpds across all servers at a particular "site".  We make some assumptions
62  * that if the site has a cluster of machines then their time is relatively
63  * synchronized.  We also assume that the first address returned by a
64  * gethostbyname (gethostname()) is unique across all the machines at the
65  * "site".
66  *
67  * We also further assume that pids fit in 32-bits.  If something uses more
68  * than 32-bits, the fix is trivial, but it requires the unrolled uuencoding
69  * loop to be extended.  * A similar fix is needed to support multithreaded
70  * servers, using a pid/tid combo.
71  *
72  * Together, the in_addr and pid are assumed to absolutely uniquely identify
73  * this one child from all other currently running children on all servers
74  * (including this physical server if it is running multiple httpds) from each
75  * other.
76  *
77  * The stamp and counter are used to distinguish all hits for a particular
78  * (in_addr,pid) pair.  The stamp is updated using r->request_time,
79  * saving cpu cycles.  The counter is never reset, and is used to permit up to
80  * 64k requests in a single second by a single child.
81  *
82  * The 112-bits of unique_id_rec are encoded using the alphabet
83  * [A-Za-z0-9@-], resulting in 19 bytes of printable characters.  That is then
84  * stuffed into the environment variable UNIQUE_ID so that it is available to
85  * other modules.  The alphabet choice differs from normal base64 encoding
86  * [A-Za-z0-9+/] because + and / are special characters in URLs and we want to
87  * make it easy to use UNIQUE_ID in URLs.
88  *
89  * Note that UNIQUE_ID should be considered an opaque token by other
90  * applications.  No attempt should be made to dissect its internal components.
91  * It is an abstraction that may change in the future as the needs of this
92  * module change.
93  *
94  * It is highly desirable that identifiers exist for "eternity".  But future
95  * needs (such as much faster webservers, moving to 64-bit pids, or moving to a
96  * multithreaded server) may dictate a need to change the contents of
97  * unique_id_rec.  Such a future implementation should ensure that the first
98  * field is still a time_t stamp.  By doing that, it is possible for a site to
99  * have a "flag second" in which they stop all of their old-format servers,
100  * wait one entire second, and then start all of their new-servers.  This
101  * procedure will ensure that the new space of identifiers is completely unique
102  * from the old space.  (Since the first four unencoded bytes always differ.)
103  */
104 /*
105  * Sun Jun  7 05:43:49 CEST 1998 -- Alvaro
106  * More comments:
107  * 1) The UUencoding prodecure is now done in a general way, avoiding the problems
108  * with sizes and paddings that can arise depending on the architecture. Now the
109  * offsets and sizes of the elements of the unique_id_rec structure are calculated
110  * in unique_id_global_init; and then used to duplicate the structure without the
111  * paddings that might exist. The multithreaded server fix should be now very easy:
112  * just add a new "tid" field to the unique_id_rec structure, and increase by one
113  * UNIQUE_ID_REC_MAX.
114  * 2) unique_id_rec.stamp has been changed from "time_t" to "unsigned int", because
115  * its size is 64bits on some platforms (linux/alpha), and this caused problems with
116  * htonl/ntohl. Well, this shouldn't be a problem till year 2106.
117  */
118
119 static unsigned global_in_addr;
120
121 static unique_id_rec cur_unique_id;
122
123 /*
124  * Number of elements in the structure unique_id_rec.
125  */
126 #define UNIQUE_ID_REC_MAX 5 
127
128 static unsigned short unique_id_rec_offset[UNIQUE_ID_REC_MAX],
129                       unique_id_rec_size[UNIQUE_ID_REC_MAX],
130                       unique_id_rec_total_size,
131                       unique_id_rec_size_uu;
132
133 static int unique_id_global_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server)
134 {
135     char str[APRMAXHOSTLEN + 1];
136     apr_status_t rv;
137     char *ipaddrstr;
138     apr_sockaddr_t *sockaddr;
139
140     /*
141      * Calculate the sizes and offsets in cur_unique_id.
142      */
143     unique_id_rec_offset[0] = APR_OFFSETOF(unique_id_rec, stamp);
144     unique_id_rec_size[0] = sizeof(cur_unique_id.stamp);
145     unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, in_addr);
146     unique_id_rec_size[1] = sizeof(cur_unique_id.in_addr);
147     unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, pid);
148     unique_id_rec_size[2] = sizeof(cur_unique_id.pid);
149     unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, counter);
150     unique_id_rec_size[3] = sizeof(cur_unique_id.counter);
151     unique_id_rec_offset[4] = APR_OFFSETOF(unique_id_rec, thread_index);
152     unique_id_rec_size[4] = sizeof(cur_unique_id.thread_index);
153     unique_id_rec_total_size = unique_id_rec_size[0] + unique_id_rec_size[1] +
154                                unique_id_rec_size[2] + unique_id_rec_size[3] +
155                                unique_id_rec_size[4];
156
157     /*
158      * Calculate the size of the structure when encoded.
159      */
160     unique_id_rec_size_uu = (unique_id_rec_total_size*8+5)/6;
161
162     /*
163      * Now get the global in_addr.  Note that it is not sufficient to use one
164      * of the addresses from the main_server, since those aren't as likely to
165      * be unique as the physical address of the machine
166      */
167     if ((rv = apr_gethostname(str, sizeof(str) - 1, p)) != APR_SUCCESS) {
168         ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server,
169           "mod_unique_id: unable to find hostname of the server");
170         return HTTP_INTERNAL_SERVER_ERROR;
171     }
172
173     if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET, 0, 0, p)) == APR_SUCCESS) {
174         global_in_addr = sockaddr->sa.sin.sin_addr.s_addr;
175     }
176     else {
177         ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server,
178                     "mod_unique_id: unable to find IPv4 address of \"%s\"", str);
179 #if APR_HAVE_IPV6
180         if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET6, 0, 0, p)) == APR_SUCCESS) {
181             memcpy(&global_in_addr,
182                    (char *)sockaddr->ipaddr_ptr + sockaddr->ipaddr_len - sizeof(global_in_addr),
183                    sizeof(global_in_addr));
184             ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server,
185                          "mod_unique_id: using low-order bits of IPv6 address "
186                          "as if they were unique");
187         }
188         else
189 #endif
190         return HTTP_INTERNAL_SERVER_ERROR;
191     }
192
193     apr_sockaddr_ip_get(&ipaddrstr, sockaddr);
194     ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server,
195                 "mod_unique_id: using ip addr %s",
196                  ipaddrstr);
197
198     /*
199      * If the server is pummelled with restart requests we could possibly end
200      * up in a situation where we're starting again during the same second
201      * that has been used in previous identifiers.  Avoid that situation.
202      * 
203      * In truth, for this to actually happen not only would it have to restart
204      * in the same second, but it would have to somehow get the same pids as
205      * one of the other servers that was running in that second. Which would
206      * mean a 64k wraparound on pids ... not very likely at all.
207      * 
208      * But protecting against it is relatively cheap.  We just sleep into the
209      * next second.
210      */
211     apr_sleep(apr_time_from_sec(1) - apr_time_usec(apr_time_now()));
212     return OK;
213 }
214
215 static void unique_id_child_init(apr_pool_t *p, server_rec *s)
216 {
217     pid_t pid;
218     apr_time_t tv;
219
220     /*
221      * Note that we use the pid because it's possible that on the same
222      * physical machine there are multiple servers (i.e. using Listen). But
223      * it's guaranteed that none of them will share the same pids between
224      * children.
225      * 
226      * XXX: for multithread this needs to use a pid/tid combo and probably
227      * needs to be expanded to 32 bits
228      */
229     pid = getpid();
230     cur_unique_id.pid = pid;
231
232     /*
233      * Test our assumption that the pid is 32-bits.  It's possible that
234      * 64-bit machines will declare pid_t to be 64 bits but only use 32
235      * of them.  It would have been really nice to test this during
236      * global_init ... but oh well.
237      */
238     if ((pid_t)cur_unique_id.pid != pid) {
239         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
240                     "oh no! pids are greater than 32-bits!  I'm broken!");
241     }
242
243     cur_unique_id.in_addr = global_in_addr;
244
245     /*
246      * If we use 0 as the initial counter we have a little less protection
247      * against restart problems, and a little less protection against a clock
248      * going backwards in time.
249      */
250     tv = apr_time_now();
251     /* Some systems have very low variance on the low end of their system
252      * counter, defend against that.
253      */
254     cur_unique_id.counter = (unsigned short)(apr_time_usec(tv) / 10);
255
256     /*
257      * We must always use network ordering for these bytes, so that
258      * identifiers are comparable between machines of different byte
259      * orderings.  Note in_addr is already in network order.
260      */
261     cur_unique_id.pid = htonl(cur_unique_id.pid);
262     cur_unique_id.counter = htons(cur_unique_id.counter);
263 }
264
265 /* NOTE: This is *NOT* the same encoding used by base64encode ... the last two
266  * characters should be + and /.  But those two characters have very special
267  * meanings in URLs, and we want to make it easy to use identifiers in
268  * URLs.  So we replace them with @ and -.
269  */
270 static const char uuencoder[64] = {
271     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
272     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
273     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
274     'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
275     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '@', '-',
276 };
277
278 static int gen_unique_id(request_rec *r)
279 {
280     char *str;
281     /*
282      * Buffer padded with two final bytes, used to copy the unique_id_red
283      * structure without the internal paddings that it could have.
284      */
285     unique_id_rec new_unique_id;
286     struct {
287         unique_id_rec foo;
288         unsigned char pad[2];
289     } paddedbuf;
290     unsigned char *x,*y;
291     unsigned short counter;
292     const char *e;
293     int i,j,k;
294
295     /* copy the unique_id if this is an internal redirect (we're never
296      * actually called for sub requests, so we don't need to test for
297      * them) */
298     if (r->prev && (e = apr_table_get(r->subprocess_env, "REDIRECT_UNIQUE_ID"))) {
299         apr_table_setn(r->subprocess_env, "UNIQUE_ID", e);
300         return DECLINED;
301     }
302     
303     new_unique_id.in_addr = cur_unique_id.in_addr;
304     new_unique_id.pid = cur_unique_id.pid;
305     new_unique_id.counter = cur_unique_id.counter;
306
307     new_unique_id.stamp = htonl((unsigned int)r->request_time);
308     new_unique_id.thread_index = htonl((unsigned int)r->connection->id);
309
310     /* we'll use a temporal buffer to avoid uuencoding the possible internal
311      * paddings of the original structure */
312     x = (unsigned char *) &paddedbuf;
313     y = (unsigned char *) &new_unique_id;
314     k = 0;
315     for (i = 0; i < UNIQUE_ID_REC_MAX; i++) {
316         y = ((unsigned char *) &new_unique_id) + unique_id_rec_offset[i];
317         for (j = 0; j < unique_id_rec_size[i]; j++, k++) {
318             x[k] = y[j];
319         }
320     }
321     /*
322      * We reset two more bytes just in case padding is needed for the uuencoding.
323      */
324     x[k++] = '\0';
325     x[k++] = '\0';
326     
327     /* alloc str and do the uuencoding */
328     str = (char *)apr_palloc(r->pool, unique_id_rec_size_uu + 1);
329     k = 0;
330     for (i = 0; i < unique_id_rec_total_size; i += 3) {
331         y = x + i;
332         str[k++] = uuencoder[y[0] >> 2];
333         str[k++] = uuencoder[((y[0] & 0x03) << 4) | ((y[1] & 0xf0) >> 4)];
334         if (k == unique_id_rec_size_uu) break;
335         str[k++] = uuencoder[((y[1] & 0x0f) << 2) | ((y[2] & 0xc0) >> 6)];
336         if (k == unique_id_rec_size_uu) break;
337         str[k++] = uuencoder[y[2] & 0x3f];
338     }
339     str[k++] = '\0';
340
341     /* set the environment variable */
342     apr_table_setn(r->subprocess_env, "UNIQUE_ID", str);
343
344     /* and increment the identifier for the next call */
345
346     counter = ntohs(new_unique_id.counter) + 1;
347     cur_unique_id.counter = htons(counter);
348
349     return DECLINED;
350 }
351
352 static void register_hooks(apr_pool_t *p)
353 {
354     ap_hook_post_config(unique_id_global_init, NULL, NULL, APR_HOOK_MIDDLE);
355     ap_hook_child_init(unique_id_child_init, NULL, NULL, APR_HOOK_MIDDLE);
356     ap_hook_post_read_request(gen_unique_id, NULL, NULL, APR_HOOK_MIDDLE); 
357 }
358
359 module AP_MODULE_DECLARE_DATA unique_id_module = {
360     STANDARD20_MODULE_STUFF,
361     NULL,                       /* dir config creater */
362     NULL,                       /* dir merger --- default is to override */
363     NULL,                       /* server config */
364     NULL,                       /* merge server configs */
365     NULL,                       /* command apr_table_t */
366     register_hooks              /* register hooks */
367 };