mod_unique_id.c revision 87e0da4e1eabf35b0b2a48a9290c5e725854de8f
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein/* ====================================================================
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * The Apache Software License, Version 1.1
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Copyright (c) 2000 The Apache Software Foundation. All rights
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * reserved.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Redistribution and use in source and binary forms, with or without
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * modification, are permitted provided that the following conditions
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * are met:
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * 1. Redistributions of source code must retain the above copyright
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * notice, this list of conditions and the following disclaimer.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * 2. Redistributions in binary form must reproduce the above copyright
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * notice, this list of conditions and the following disclaimer in
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * the documentation and/or other materials provided with the
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * distribution.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * 3. The end-user documentation included with the redistribution,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * if any, must include the following acknowledgment:
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * "This product includes software developed by the
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Apache Software Foundation (http://www.apache.org/)."
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Alternately, this acknowledgment may appear in the software itself,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * if and wherever such third-party acknowledgments normally appear.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * 4. The names "Apache" and "Apache Software Foundation" must
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * not be used to endorse or promote products derived from this
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * software without prior written permission. For written
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * permission, please contact apache@apache.org.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * 5. Products derived from this software may not be called "Apache",
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * nor may "Apache" appear in their name, without prior written
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * permission of the Apache Software Foundation.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * SUCH DAMAGE.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * ====================================================================
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * This software consists of voluntary contributions made by many
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * individuals on behalf of the Apache Software Foundation. For more
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * information on the Apache Software Foundation, please see
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * <http://www.apache.org/>.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Portions of this software are based upon public domain software
f4c310fd2555c6faca1f980f00b161eadb089023gstein * originally written at the National Center for Supercomputing Applications,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * University of Illinois, Urbana-Champaign.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein/*
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * mod_unique_id.c: generate a unique identifier for each request
8a46775d163c06a8c51d1b0a3f2edfde945cb1d8stoddard *
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein * Original author: Dean Gaudet <dgaudet@arctic.org>
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein * UUencoding modified by: Alvaro Martinez Echevarria <alvaro@lander.es>
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein */
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein#include "httpd.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_config.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_log.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef struct {
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned int stamp;
1a9d922232824a7cc008d4f74e48bd82adf5bdedgstein unsigned int in_addr;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein unsigned int pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned short counter;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned int thread_index;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} unique_id_rec;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* We are using thread_index (the index into the scoreboard), because we
f4c310fd2555c6faca1f980f00b161eadb089023gstein * cannont garauntee the thread_id will be an integer.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This code looks like it won't give a unique ID with the new thread logic.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * It will. The reason is, we don't increment the counter in a thread_safe
f4c310fd2555c6faca1f980f00b161eadb089023gstein * manner. Because the thread_index is also in the unique ID now, this does
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * not matter. In order for the id to not be unique, the same thread would
f4c310fd2555c6faca1f980f00b161eadb089023gstein * have to get the same counter twice in the same second.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Comments:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * We want an identifier which is unique across all hits, everywhere.
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * "everywhere" includes multiple httpd instances on the same machine, or on
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * multiple machines. Essentially "everywhere" should include all possible
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * httpds across all servers at a particular "site". We make some assumptions
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * that if the site has a cluster of machines then their time is relatively
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * synchronized. We also assume that the first address returned by a
f4c310fd2555c6faca1f980f00b161eadb089023gstein * gethostbyname (gethostname()) is unique across all the machines at the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * "site".
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * We also further assume that pids fit in 32-bits. If something uses more
707ecf9559338ec06b24334bc9abcca670325cc4gstein * than 32-bits, the fix is trivial, but it requires the unrolled uuencoding
f4c310fd2555c6faca1f980f00b161eadb089023gstein * loop to be extended. * A similar fix is needed to support multithreaded
707ecf9559338ec06b24334bc9abcca670325cc4gstein * servers, using a pid/tid combo.
707ecf9559338ec06b24334bc9abcca670325cc4gstein *
707ecf9559338ec06b24334bc9abcca670325cc4gstein * Together, the in_addr and pid are assumed to absolutely uniquely identify
707ecf9559338ec06b24334bc9abcca670325cc4gstein * this one child from all other currently running children on all servers
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * (including this physical server if it is running multiple httpds) from each
f4c310fd2555c6faca1f980f00b161eadb089023gstein * other.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * The stamp and counter are used to distinguish all hits for a particular
f4c310fd2555c6faca1f980f00b161eadb089023gstein * (in_addr,pid) pair. The stamp is updated using r->request_time,
707ecf9559338ec06b24334bc9abcca670325cc4gstein * saving cpu cycles. The counter is never reset, and is used to permit up to
707ecf9559338ec06b24334bc9abcca670325cc4gstein * 64k requests in a single second by a single child.
707ecf9559338ec06b24334bc9abcca670325cc4gstein *
707ecf9559338ec06b24334bc9abcca670325cc4gstein * The 112-bits of unique_id_rec are encoded using the alphabet
707ecf9559338ec06b24334bc9abcca670325cc4gstein * [A-Za-z0-9@-], resulting in 19 bytes of printable characters. That is then
707ecf9559338ec06b24334bc9abcca670325cc4gstein * stuffed into the environment variable UNIQUE_ID so that it is available to
707ecf9559338ec06b24334bc9abcca670325cc4gstein * other modules. The alphabet choice differs from normal base64 encoding
707ecf9559338ec06b24334bc9abcca670325cc4gstein * [A-Za-z0-9+/] because + and / are special characters in URLs and we want to
707ecf9559338ec06b24334bc9abcca670325cc4gstein * make it easy to use UNIQUE_ID in URLs.
707ecf9559338ec06b24334bc9abcca670325cc4gstein *
707ecf9559338ec06b24334bc9abcca670325cc4gstein * Note that UNIQUE_ID should be considered an opaque token by other
707ecf9559338ec06b24334bc9abcca670325cc4gstein * applications. No attempt should be made to dissect its internal components.
707ecf9559338ec06b24334bc9abcca670325cc4gstein * It is an abstraction that may change in the future as the needs of this
707ecf9559338ec06b24334bc9abcca670325cc4gstein * module change.
707ecf9559338ec06b24334bc9abcca670325cc4gstein *
707ecf9559338ec06b24334bc9abcca670325cc4gstein * It is highly desirable that identifiers exist for "eternity". But future
707ecf9559338ec06b24334bc9abcca670325cc4gstein * needs (such as much faster webservers, moving to 64-bit pids, or moving to a
707ecf9559338ec06b24334bc9abcca670325cc4gstein * multithreaded server) may dictate a need to change the contents of
707ecf9559338ec06b24334bc9abcca670325cc4gstein * unique_id_rec. Such a future implementation should ensure that the first
707ecf9559338ec06b24334bc9abcca670325cc4gstein * field is still a time_t stamp. By doing that, it is possible for a site to
707ecf9559338ec06b24334bc9abcca670325cc4gstein * have a "flag second" in which they stop all of their old-format servers,
707ecf9559338ec06b24334bc9abcca670325cc4gstein * wait one entire second, and then start all of their new-servers. This
f4c310fd2555c6faca1f980f00b161eadb089023gstein * procedure will ensure that the new space of identifiers is completely unique
f4c310fd2555c6faca1f980f00b161eadb089023gstein * from the old space. (Since the first four unencoded bytes always differ.)
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Sun Jun 7 05:43:49 CEST 1998 -- Alvaro
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * More comments:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * 1) The UUencoding prodecure is now done in a general way, avoiding the problems
f4c310fd2555c6faca1f980f00b161eadb089023gstein * with sizes and paddings that can arise depending on the architecture. Now the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * offsets and sizes of the elements of the unique_id_rec structure are calculated
f4c310fd2555c6faca1f980f00b161eadb089023gstein * in unique_id_global_init; and then used to duplicate the structure without the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * paddings that might exist. The multithreaded server fix should be now very easy:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * just add a new "tid" field to the unique_id_rec structure, and increase by one
f4c310fd2555c6faca1f980f00b161eadb089023gstein * UNIQUE_ID_REC_MAX.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * 2) unique_id_rec.stamp has been changed from "time_t" to "unsigned int", because
f4c310fd2555c6faca1f980f00b161eadb089023gstein * its size is 64bits on some platforms (linux/alpha), and this caused problems with
f4c310fd2555c6faca1f980f00b161eadb089023gstein * htonl/ntohl. Well, this shouldn't be a problem till year 2106.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic unsigned global_in_addr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic unique_id_rec cur_unique_id;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Number of elements in the structure unique_id_rec.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define UNIQUE_ID_REC_MAX 5
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic unsigned short unique_id_rec_offset[UNIQUE_ID_REC_MAX],
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[UNIQUE_ID_REC_MAX],
f4c310fd2555c6faca1f980f00b161eadb089023gstein unique_id_rec_total_size,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size_uu;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic void unique_id_global_init(ap_pool_t *p, ap_pool_t *plog, ap_pool_t *ptemp, server_rec *main_server)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein{
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#ifndef MAXHOSTNAMELEN
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define MAXHOSTNAMELEN 256
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#endif
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein char str[MAXHOSTNAMELEN + 1];
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein struct hostent *hent;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein ap_time_t tv;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /*
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * Calculate the sizes and offsets in cur_unique_id.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_offset[0] = XtOffsetOf(unique_id_rec, stamp);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[0] = sizeof(cur_unique_id.stamp);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_offset[1] = XtOffsetOf(unique_id_rec, in_addr);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[1] = sizeof(cur_unique_id.in_addr);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_offset[2] = XtOffsetOf(unique_id_rec, pid);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[2] = sizeof(cur_unique_id.pid);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_offset[3] = XtOffsetOf(unique_id_rec, counter);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[3] = sizeof(cur_unique_id.counter);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_offset[4] = XtOffsetOf(unique_id_rec, thread_index);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[4] = sizeof(cur_unique_id.thread_index);
f4c310fd2555c6faca1f980f00b161eadb089023gstein unique_id_rec_total_size = unique_id_rec_size[0] + unique_id_rec_size[1] +
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[2] + unique_id_rec_size[3] +
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein unique_id_rec_size[4];
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /*
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein * Calculate the size of the structure when encoded.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein unique_id_rec_size_uu = (unique_id_rec_total_size*8+5)/6;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Now get the global in_addr. Note that it is not sufficient to use one
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * of the addresses from the main_server, since those aren't as likely to
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * be unique as the physical address of the machine
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein if (gethostname(str, sizeof(str) - 1) != 0) {
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, errno, main_server,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein "gethostname: mod_unique_id requires the hostname of the server");
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein exit(1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein str[sizeof(str) - 1] = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if ((hent = gethostbyname(str)) == NULL) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, h_errno, main_server,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "mod_unique_id: unable to gethostbyname(\"%s\")", str);
f4c310fd2555c6faca1f980f00b161eadb089023gstein exit(1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein global_in_addr = ((struct in_addr *) hent->h_addr_list[0])->s_addr;
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein
707ecf9559338ec06b24334bc9abcca670325cc4gstein ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, main_server,
707ecf9559338ec06b24334bc9abcca670325cc4gstein "mod_unique_id: using ip addr %s",
707ecf9559338ec06b24334bc9abcca670325cc4gstein inet_ntoa(*(struct in_addr *) hent->h_addr_list[0]));
707ecf9559338ec06b24334bc9abcca670325cc4gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If the server is pummelled with restart requests we could possibly end
f4c310fd2555c6faca1f980f00b161eadb089023gstein * up in a situation where we're starting again during the same second
f4c310fd2555c6faca1f980f00b161eadb089023gstein * that has been used in previous identifiers. Avoid that situation.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * In truth, for this to actually happen not only would it have to restart
f4c310fd2555c6faca1f980f00b161eadb089023gstein * in the same second, but it would have to somehow get the same pids as
f4c310fd2555c6faca1f980f00b161eadb089023gstein * one of the other servers that was running in that second. Which would
f4c310fd2555c6faca1f980f00b161eadb089023gstein * mean a 64k wraparound on pids ... not very likely at all.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * But protecting against it is relatively cheap. We just sleep into the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * next second.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein tv = ap_now();
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_sleep(
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void unique_id_child_init(ap_pool_t *p, server_rec *s)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein pid_t pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein time_t tv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Note that we use the pid because it's possible that on the same
f4c310fd2555c6faca1f980f00b161eadb089023gstein * physical machine there are multiple servers (i.e. using Listen). But
f4c310fd2555c6faca1f980f00b161eadb089023gstein * it's guaranteed that none of them will share the same pids between
f4c310fd2555c6faca1f980f00b161eadb089023gstein * children.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * XXX: for multithread this needs to use a pid/tid combo and probably
49bf4df23d9e5281abcd83005550bda818b17b08wrowe * needs to be expanded to 32 bits
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein pid = getpid();
f4c310fd2555c6faca1f980f00b161eadb089023gstein cur_unique_id.pid = pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Test our assumption that the pid is 32-bits. It's possible that
f4c310fd2555c6faca1f980f00b161eadb089023gstein * 64-bit machines will declare pid_t to be 64 bits but only use 32
f4c310fd2555c6faca1f980f00b161eadb089023gstein * of them. It would have been really nice to test this during
f4c310fd2555c6faca1f980f00b161eadb089023gstein * global_init ... but oh well.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (cur_unique_id.pid != pid) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, 0, s,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "oh no! pids are greater than 32-bits! I'm broken!");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm cur_unique_id.in_addr = global_in_addr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
53dafcfda483886730db8e57bf6f94cff36f0047stoddard /*
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein * If we use 0 as the initial counter we have a little less protection
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein * against restart problems, and a little less protection against a clock
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * going backwards in time.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein tv = ap_now();
f4c310fd2555c6faca1f980f00b161eadb089023gstein cur_unique_id.counter = tv % APR_USEC_PER_SEC / 10;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * We must always use network ordering for these bytes, so that
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein * identifiers are comparable between machines of different byte
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein * orderings. Note in_addr is already in network order.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein cur_unique_id.pid = htonl(cur_unique_id.pid);
f4c310fd2555c6faca1f980f00b161eadb089023gstein cur_unique_id.counter = htons(cur_unique_id.counter);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* NOTE: This is *NOT* the same encoding used by base64encode ... the last two
f4c310fd2555c6faca1f980f00b161eadb089023gstein * characters should be + and /. But those two characters have very special
f4c310fd2555c6faca1f980f00b161eadb089023gstein * meanings in URLs, and we want to make it easy to use identifiers in
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe * URLs. So we replace them with @ and -.
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe */
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gsteinstatic const char uuencoder[64] = {
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
f4c310fd2555c6faca1f980f00b161eadb089023gstein 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
f4c310fd2555c6faca1f980f00b161eadb089023gstein 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
f4c310fd2555c6faca1f980f00b161eadb089023gstein 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
f4c310fd2555c6faca1f980f00b161eadb089023gstein '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '@', '-',
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int gen_unique_id(request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *str;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Buffer padded with two final bytes, used to copy the unique_id_red
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * structure without the internal paddings that it could have.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein unique_id_rec new_unique_id;
f4c310fd2555c6faca1f980f00b161eadb089023gstein struct {
f4c310fd2555c6faca1f980f00b161eadb089023gstein unique_id_rec foo;
f4c310fd2555c6faca1f980f00b161eadb089023gstein unsigned char pad[2];
f4c310fd2555c6faca1f980f00b161eadb089023gstein } paddedbuf;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm unsigned char *x,*y;
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein unsigned short counter;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *e;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i,j,k;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* copy the unique_id if this is an internal redirect (we're never
f4c310fd2555c6faca1f980f00b161eadb089023gstein * actually called for sub requests, so we don't need to test for
f4c310fd2555c6faca1f980f00b161eadb089023gstein * them) */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (r->prev && (e = ap_table_get(r->subprocess_env, "REDIRECT_UNIQUE_ID"))) {
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein ap_table_setn(r->subprocess_env, "UNIQUE_ID", e);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm return DECLINED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_unique_id.in_addr = cur_unique_id.in_addr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_unique_id.pid = cur_unique_id.pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_unique_id.counter = cur_unique_id.counter;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_unique_id.stamp = htonl((unsigned int)r->request_time);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm new_unique_id.thread_index = htonl((unsigned int)r->connection->id);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein /* we'll use a temporal buffer to avoid uuencoding the possible internal
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * paddings of the original structure */
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein x = (unsigned char *) &paddedbuf;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm y = (unsigned char *) &new_unique_id;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm k = 0;
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein for (i = 0; i < UNIQUE_ID_REC_MAX; i++) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm y = ((unsigned char *) &new_unique_id) + unique_id_rec_offset[i];
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (j = 0; j < unique_id_rec_size[i]; j++, k++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein x[k] = y[j];
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * We reset two more bytes just in case padding is needed for the uuencoding.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein x[k++] = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein x[k++] = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* alloc str and do the uuencoding */
f4c310fd2555c6faca1f980f00b161eadb089023gstein str = (char *)ap_palloc(r->pool, unique_id_rec_size_uu + 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein k = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < unique_id_rec_total_size; i += 3) {
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein y = x + i;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm str[k++] = uuencoder[y[0] >> 2];
f4c310fd2555c6faca1f980f00b161eadb089023gstein str[k++] = uuencoder[((y[0] & 0x03) << 4) | ((y[1] & 0xf0) >> 4)];
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (k == unique_id_rec_size_uu) break;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm str[k++] = uuencoder[((y[1] & 0x0f) << 2) | ((y[2] & 0xc0) >> 6)];
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (k == unique_id_rec_size_uu) break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein str[k++] = uuencoder[y[2] & 0x3f];
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein str[k++] = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* set the environment variable */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_table_setn(r->subprocess_env, "UNIQUE_ID", str);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* and increment the identifier for the next call */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein counter = ntohs(new_unique_id.counter) + 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein cur_unique_id.counter = htons(counter);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return DECLINED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void register_hooks(void)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_post_config(unique_id_global_init, NULL, NULL, AP_HOOK_MIDDLE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_child_init(unique_id_child_init, NULL, NULL, AP_HOOK_MIDDLE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_post_read_request(gen_unique_id, NULL, NULL, AP_HOOK_MIDDLE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agsteinmodule MODULE_VAR_EXPORT unique_id_module = {
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein STANDARD20_MODULE_STUFF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, /* dir config creater */
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, /* dir merger --- default is to override */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm NULL, /* server config */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm NULL, /* merge server configs */
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, /* command ap_table_t */
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, /* handlers */
f4c310fd2555c6faca1f980f00b161eadb089023gstein register_hooks /* register hooks */
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein