httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject [PATCH] mod_unique_id.c
Date Sat, 16 Aug 1997 19:13:53 GMT
Ok I'll take Ben's advice and call these unique identifiers.  This patch
implements the stuff I've been babbling about, so that people can see
exactly what I mean in code and tell me if I'm smoking crack. 

I add a new API phase -- post_read_request.  It runs after read_request or
internal_redirect are done setting up the request.  It does not run for
subrequests, because they inherit the environment of the parent.  I
proposed this phase a while back as the "correct" solution to the
mod_browser/mod_setenvif dilemna that I had when fixing the MSIE 4.0b2
problems.  Specifically, the header_parse phase occurs far too late to
affect some aspects of the protocol (i.e. far too late for a nokeepalive
env var to be set to stop a redirect response from being kept-alive). 

Incidentally this phase would also fix the "mod_browser is run too many
times" problem... but we fixed that already another way
(is_initial_request)... which wasn't copied to mod_setenvif.  No biggie,
'cause this patch fixes that. 

I really wanted to log an informational message indicating what ip is
being used to generate the sequence number.  But if I did a log_printf
during init_modules() it would get stuffed on stderr twice, and never be
logged!  I don't think that is right ... so I swapped the order of
init_modules and open_logs (which opens just the error logs).  But that
still would cause it to be dumped on stderr during the first round of
config reading... so the first round now does not call init_modules.  I
can't imagine this breaking anything.

Without further ado, the patch.  With a well-commented mod_unique_id.c. 

Dean

Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apachen/src/CHANGES,v
retrieving revision 1.397
diff -u -r1.397 CHANGES
--- CHANGES	1997/08/15 18:12:04	1.397
+++ CHANGES	1997/08/16 19:05:24
@@ -1,4 +1,21 @@
 Changes with Apache 1.3a2
+  
+  *) API: Added post_read_request API phase which is run right after reading
+     the request from a client, or right after an internal redirect.  It is
+     useful for modules setting environment variables that depend only on
+     the headers/contents of the request.  It does not run during subrequests
+     because subrequests inherit pretty much everything from the main
+     request. [Dean Gaudet]
+  
+  *) Added mod_unique_id which is used to generate a unique identifier for
+     each hit, available in the environment variable UNIQUE_ID.
+     [Dean Gaudet]
+  
+  *) init_modules is now called after the error logs have been opened.  This
+     allows modules to emit information messages into the error logs.
+     init_modules is only called once in standalone config now, previously
+     it was called twice (once after each config file reading).
+     [Dean Gaudet]
 
   *) Configure changes: TestLib replaced by TestCompile, which has
      some additional capability (such as doing a sanity check of
Index: Configuration.tmpl
===================================================================
RCS file: /export/home/cvs/apachen/src/Configuration.tmpl,v
retrieving revision 1.71
diff -u -r1.71 Configuration.tmpl
--- Configuration.tmpl	1997/08/10 13:29:51	1.71
+++ Configuration.tmpl	1997/08/16 19:05:25
@@ -300,3 +300,9 @@
 ## should be the last (highest priority) module.
 
 AddModule modules/standard/mod_setenvif.o
+
+## mod_unique_id generates unique identifiers for each hit, which are
+## available in the environment variable UNIQUE_ID.  It may not work on all
+## systems, hence it is not included by default.
+
+# AddModule modules/standard/mod_unique_id.o
Index: core/http_config.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_config.c,v
retrieving revision 1.72
diff -u -r1.72 http_config.c
--- http_config.c	1997/08/06 20:21:21	1.72
+++ http_config.c	1997/08/16 19:05:28
@@ -259,7 +259,8 @@
     XtOffsetOf (module, type_checker),
     XtOffsetOf (module, fixer_upper),
     XtOffsetOf (module, logger),
-    XtOffsetOf (module, header_parser)
+    XtOffsetOf (module, header_parser),
+    XtOffsetOf (module, post_read_request)
 };
 #define NMETHODS	(sizeof (method_offsets)/sizeof (method_offsets[0]))
 
@@ -272,6 +273,7 @@
     int fixer_upper;
     int logger;
     int header_parser;
+    int post_read_request;
 } offsets_into_method_ptrs;
 
 /*
@@ -370,6 +372,10 @@
 
 int header_parse (request_rec *r) {
     return run_method (r, offsets_into_method_ptrs.header_parser, 1);
+}
+
+int run_post_read_request (request_rec *r) {
+    return run_method (r, offsets_into_method_ptrs.post_read_request, 1);
 }
 
 /* Auth stuff --- anything that defines one of these will presumably
Index: core/http_config.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_config.h,v
retrieving revision 1.43
diff -u -r1.43 http_config.h
--- http_config.h	1997/08/06 20:21:23	1.43
+++ http_config.h	1997/08/16 19:05:29
@@ -205,8 +205,9 @@
      *                  supposed to handle this was configured wrong).
      * type_checker --- Determine MIME type of the requested entity;
      *                  sets content_type, _encoding and _language fields.
-     * logger --- log a transaction.  Not supported yet out of sheer
-     *            laziness on my part.
+     * logger --- log a transaction.
+     * post_read_request --- run right after read_request or internal_redirect,
+     *                  and not run during any subrequests.
      */
     
     int (*translate_handler)(request_rec *);
@@ -230,15 +231,12 @@
      */
 #ifdef ULTRIX_BRAIN_DEATH
     void (*child_init)();
-#else
-    void (*child_init)(server_rec *, pool *);
-#endif
-#ifdef ULTRIX_BRAIN_DEATH
     void (*child_exit)();
 #else
+    void (*child_init)(server_rec *, pool *);
     void (*child_exit)(server_rec *, pool *);
 #endif
-
+    int (*post_read_request)(request_rec *);
 } module;
 
 /* Initializer for the first few module slots, which are only
@@ -323,5 +321,6 @@
 int invoke_handler (request_rec *);     
 int log_transaction (request_rec *r);
 int header_parse (request_rec *);
+int run_post_read_request (request_rec *);
 
 #endif
Index: core/http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_main.c,v
retrieving revision 1.200
diff -u -r1.200 http_main.c
--- http_main.c	1997/08/15 18:12:11	1.200
+++ http_main.c	1997/08/16 19:05:37
@@ -2803,8 +2803,8 @@
 
 	server_conf = read_config (pconf, ptrans, server_confname); 
 	setup_listeners (pconf);
-	init_modules (pconf, server_conf);
 	open_logs (server_conf, pconf);
+	init_modules (pconf, server_conf);
 	set_group_privs ();
 	accept_mutex_init (pconf);
 	if (!is_graceful) {
@@ -3024,7 +3024,6 @@
 
     suexec_enabled = init_suexec();
     server_conf = read_config (pconf, ptrans, server_confname);
-    init_modules (pconf, server_conf);
     
     if(standalone) {
         clear_pool (pconf);	/* standalone_main rereads... */
@@ -3038,6 +3037,7 @@
 	NET_SIZE_T l;
       
 	open_logs(server_conf, pconf);
+	init_modules (pconf, server_conf);
 	set_group_privs();
 	default_server_hostnames (server_conf);
 
Index: core/http_protocol.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_protocol.c,v
retrieving revision 1.152
diff -u -r1.152 http_protocol.c
--- http_protocol.c	1997/08/15 17:59:50	1.152
+++ http_protocol.c	1997/08/16 19:05:43
@@ -796,6 +796,7 @@
 request_rec *read_request (conn_rec *conn)
 {
     request_rec *r = (request_rec *)pcalloc (conn->pool, sizeof(request_rec));
+    int access_status;
 
     r->connection = conn;
     conn->server = conn->base_server;
@@ -880,6 +881,11 @@
         r->method_number = M_TRACE;
     else 
         r->method_number = M_INVALID; /* Will eventually croak. */
+
+    if ((access_status = run_post_read_request (r))) {
+	die (access_status, r);
+	return NULL;
+    }
 
     return r;
 }
Index: core/http_request.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_request.c,v
retrieving revision 1.74
diff -u -r1.74 http_request.c
--- http_request.c	1997/08/09 11:52:04	1.74
+++ http_request.c	1997/08/16 19:05:45
@@ -923,7 +923,7 @@
 void process_request_internal (request_rec *r)
 {
     int access_status;
-  
+
     /* Kludge to be reading the assbackwards field outside of protocol.c,
      * but we've got to check for this sort of nonsense somewhere...
      */
@@ -1112,6 +1112,7 @@
 {
     request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec));
     char t[256];		/* Long enough... */
+    int access_status;
   
     new->connection = r->connection;
     new->server = r->server;
@@ -1163,6 +1164,15 @@
 
     ap_snprintf (t, sizeof(t), "%d", r->status);
     table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t));
+
+    /* XXX: hmm.  This is because mod_setenvif and mod_unique_id really need
+     * to do their thing on internal redirects as well.  Perhaps this is
+     * a misnamed function.
+     */
+    if ((access_status = run_post_read_request (new))) {
+	die (access_status, new);
+	return NULL;
+    }
 
     return new;
 }
Index: core/http_request.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_request.h,v
retrieving revision 1.13
diff -u -r1.13 http_request.h
--- http_request.h	1997/07/15 21:39:57	1.13
+++ http_request.h	1997/08/16 19:05:46
@@ -92,4 +92,5 @@
 /* Function called by main.c to handle first-level request */
 void process_request (request_rec *);     
 int default_handler (request_rec *);
+void die(int type, request_rec *r);
 #endif
Index: modules/standard/mod_setenvif.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/standard/mod_setenvif.c,v
retrieving revision 1.4
diff -u -r1.4 mod_setenvif.c
--- mod_setenvif.c	1997/08/02 08:10:28	1.4
+++ mod_setenvif.c	1997/08/16 19:05:47
@@ -269,7 +269,7 @@
 { NULL },
 };
 
-static int fname_translate_setenvif(request_rec *r)
+static int match_headers(request_rec *r)
 {
     server_rec *s = r->server;
     sei_cfg_rec *sconf = (sei_cfg_rec *)get_module_config(s->module_config,
@@ -342,7 +342,7 @@
    merge_setenvif_config,     	/* merge server configs */
    setenvif_module_cmds,	/* command table */
    NULL,			/* handlers */
-   fname_translate_setenvif,	/* filename translation */
+   NULL,			/* filename translation */
    NULL,			/* check_user_id */
    NULL,			/* check auth */
    NULL,			/* check access */
@@ -350,6 +350,7 @@
    NULL,			/* fixups */
    NULL,			/* logger */
    NULL,			/* browser parse */
-   NULL,			/* child (process) initializer */
-   NULL				/* child (process) rundown handler */
+   NULL,			/* child_init */
+   NULL,			/* child_exit */
+   match_headers		/* post_read_request */
 };
Index: modules/standard/mod_unique_id.c
===================================================================
RCS file: mod_unique_id.c
diff -N mod_unique_id.c
--- /dev/null	Sat Aug 16 12:05:00 1997
+++ mod_unique_id.c	Sat Aug 16 12:05:48 1997
@@ -0,0 +1,319 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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.
+ *
+ * 5. 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/>.
+ *
+ */
+
+/*
+ * mod_uniqueid.c: generate a unique identifier for each request
+ *
+ * Original author: Dean Gaudet <dgaudet@arctic.org>
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "multithread.h"
+#include <unistd.h>
+#include <netdb.h>
+
+#ifdef MULTITHREAD
+#error sorry this module does not support multithreaded servers yet
+#endif
+
+typedef struct {
+    time_t stamp;
+    unsigned in_addr;
+    unsigned short pid;
+    unsigned short counter;
+} unique_id_rec;
+
+/* Comments:
+ *
+ * We want an identifier which is unique across all hits, everywhere.
+ * "everywhere" includes multiple httpd instances on the same machine, or on
+ * multiple machines.  Essentially "everywhere" should include all possible
+ * httpds across all servers at a particular "site".  We make some assumptions
+ * that if the site has a cluster of machines then their time is relatively
+ * synchronized.  We also assume that the first address returned by a
+ * gethostbyname (gethostname()) is unique across all the machines at the
+ * "site".
+ *
+ * We also further assume that pids are 16-bits.  The fix for this is pretty
+ * trivial, but it does increase the uuencoded identifier from 16 bytes to 19
+ * bytes.  A similar fix is needed to support multithreaded servers, using a
+ * pid/tid combo.
+ *
+ * Together, the in_addr and pid are assumed to absolutely uniquely identify
+ * this one child from all other currently running children on all servers
+ * (including this physical server if it is running multiple httpds) from each
+ * other.
+ *
+ * The stamp and counter are used to distinguish all hits for a particular
+ * (in_addr,pid) pair.  The stamp is only updated when the counter rolls over,
+ * saving cpu cycles.  This allows a single child to serve 64k requests in a
+ * single second without any overlap occuring.
+ *
+ * The 96-bits of unique_id_rec are uuencoded using the alphabet [A-Za-z0-9@-],
+ * resulting in 16 bytes of printable characters.  That is then stuffed into
+ * the environment variable UNIQUE_ID so that it is available to other modules.
+ * The alphabet choice differs from normal base64 encoding [A-Za-z0-9+/]
+ * because + and / are special characters in URLs and we want to make it easy
+ * to use UNIQUE_ID in URLs.
+ *
+ * Note that UNIQUE_ID should be considered an opaque token by other
+ * applications.  No attempt should be made to dissect its internal components.
+ * It is an abstraction that may change in the future as the needs of this
+ * module change.
+ *
+ * It is highly desirable that identifiers exist for "eternity".  But future
+ * needs (such as much faster webservers, moving to 32-bit pids, or moving to a
+ * multithreaded server) may dictate a need to change the contents of
+ * unique_id_rec.  Such a future implementation should ensure that the first
+ * field is still a time_t stamp.  By doing that, it is possible for a site to
+ * have a "flag second" in which they stop all of their old-format servers,
+ * wait one entire second, and then start all of their new-servers.  This
+ * procedure will ensure that the new space of identifiers is completely unique
+ * from the old space.  (Since the first four unencoded bytes always differ.)
+ */
+
+static unsigned global_in_addr;
+
+static APACHE_TLS unsigned short rollover_at;
+static APACHE_TLS unique_id_rec cur_unique_id;
+
+static void unique_id_global_init (server_rec *s, pool *p)
+{
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+    char str[MAXHOSTNAMELEN+1];
+    struct hostent *hent;
+    
+    /* First of all, verify some assumptions that have been made about
+     * the contents of unique_id_rec
+     */
+    if (sizeof (unique_id_rec) != 12) {
+	log_error ("mod_unique_id: sorry the size assumptions are wrong in mod_unique_id.c, please
remove it from your server or fix the code!", s);
+	exit (1);
+    }
+
+    /* Now get the global in_addr.  Note that it is not sufficient to use
+     * one of the addresses from the main_server, since those aren't as likely
+     * to be unique as the physical address of the machine
+     */
+    if (gethostname (str, sizeof (str) - 1) != 0) {
+	log_unixerr ("gethostname", "mod_unique_id",
+	    "mod_unique_id requires the hostname of the server", s);
+	exit (1);
+    }
+
+    if ((hent = gethostbyname (str)) == NULL) {
+	log_printf (s, "mod_unique_id: unable to gethostbyname(\"%s\")", str);
+	exit (1);
+    }
+
+    global_in_addr = ((struct in_addr *)hent->h_addr_list[0])->s_addr;
+
+    log_printf (s, "mod_unique_id: using ip addr %s",
+	inet_ntoa (*(struct in_addr *)hent->h_addr_list[0]));
+
+    /* If the server is pummelled with restart requests we could possibly
+     * end up in a situation where we're starting again during the same
+     * second that has been used in previous identifiers.  Avoid that
+     * situation.
+     *
+     * In truth, for this to actually happen not only would it have to
+     * restart in the same second, but it would have to somehow get the
+     * same pids as one of the other servers that was running in that second.
+     * Which would mean a 64k wraparound on pids ... not very likely at
+     * all.
+     *
+     * But protecting against it is relatively cheap.
+     */
+    sleep (1);
+}
+
+static void unique_id_child_init (server_rec *s, pool *p)
+{
+    pid_t pid;
+    struct timeval tv;
+
+    /* Note that we use the pid because it's possible that on the same
+     * physical machine there are multiple servers (i.e. using Listen).
+     * But it's guaranteed that none of them will share the same pids
+     * between children.
+     *
+     * XXX: for multithread this needs to use a pid/tid combo and probably
+     * XXX: needs to be expanded to 32 bits
+     */
+    pid = getpid();
+    cur_unique_id.pid = pid;
+
+    /* Test our assumption that the pid is 16-bits.  But note we can't just
+     * test sizeof (pid_t) because on some machines pid_t is 32-bits but
+     * pids are actually only 16-bits.  It would have been really nice to
+     * test this during global_init ... but oh well.
+     */
+    if (cur_unique_id.pid != pid) {
+	log_error ("mod_unique_id: oh no! pids are greater than 16-bits!  I'm broken!", s);
+    }
+
+    cur_unique_id.in_addr = global_in_addr;
+
+    /* If we use 0 as the initial counter we have a little less protection
+     * against restart problems, and a little less protection against a
+     * clock going backwards in time.
+     */
+    if (gettimeofday (&tv, NULL) == -1) {
+	/* ugh */
+	cur_unique_id.stamp = time(0);
+	cur_unique_id.counter = 0;
+    } else {
+	cur_unique_id.stamp = tv.tv_sec;
+	cur_unique_id.counter = tv.tv_usec;
+    }
+
+    /* And just remember this so that we consider it to be our rollover
+     * point, when we'll update the timestamp.
+     */
+    rollover_at = cur_unique_id.counter;
+
+    /* We must always use network ordering for these bytes, so that identifiers
+     * are comparable between machines of different byte orderings.  Note
+     * in_addr is already in network order.
+     */
+    cur_unique_id.stamp = htonl (cur_unique_id.stamp);
+    cur_unique_id.pid = htons (cur_unique_id.pid);
+    cur_unique_id.counter = htons (cur_unique_id.counter);
+}
+
+/* NOTE: This is *NOT* the same encoding used by uuencode ... the last two
+ * characters should be + and /.  But those two characters have very special
+ * meanings in URLs, and we want to make it easy to use identifiers in
+ * URLs.  So we replace them with @ and -.
+ */
+static const char uuencoder[64] = {
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '@', '-',
+};
+
+static int gen_unique_id (request_rec *r)
+{
+    /* when we uuencode it will take 16 bytes plus \0 */
+    char str[16 + 1];
+    const unsigned char *x;
+    unsigned short counter;
+
+    /* do the uuencoding */
+    x = (const unsigned char *)&cur_unique_id;
+    str[0] = uuencoder[x[0] >> 2];
+    str[1] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)];
+    str[2] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)];
+    str[3] = uuencoder[x[2] & 0x3f];
+    x += 3;
+    str[4] = uuencoder[x[0] >> 2];
+    str[5] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)];
+    str[6] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)];
+    str[7] = uuencoder[x[2] & 0x3f];
+    x += 3;
+    str[8] = uuencoder[x[0] >> 2];
+    str[9] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)];
+    str[10] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)];
+    str[11] = uuencoder[x[2] & 0x3f];
+    x += 3;
+    str[12] = uuencoder[x[0] >> 2];
+    str[13] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)];
+    str[14] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)];
+    str[15] = uuencoder[x[2] & 0x3f];
+    str[16] = '\0';
+
+    table_set (r->subprocess_env, "UNIQUE_ID", str);
+
+    /* and increment the identifier for the next call */
+    counter = ntohs (cur_unique_id.counter);
+    if (++counter == rollover_at) {
+	time_t now = time(0);
+
+	if (now == ntohl (cur_unique_id.stamp)) {
+	    log_error ("mod_unique_id: oh wow, somehow a single child served 64k hits in one second",
r->server);
+	    sleep(1);
+	}
+	cur_unique_id.stamp = htonl (now);
+    }
+    cur_unique_id.counter = htons (counter);
+
+    return DECLINED;
+}
+
+
+module MODULE_VAR_EXPORT unique_id_module = {
+   STANDARD_MODULE_STUFF,
+   unique_id_global_init,	/* initializer */
+   NULL,			/* dir config creater */
+   NULL,			/* dir merger --- default is to override */
+   NULL,			/* server config */
+   NULL,			/* merge server configs */
+   NULL,			/* command table */
+   NULL,			/* handlers */
+   NULL,			/* filename translation */
+   NULL,			/* check_user_id */
+   NULL,			/* check auth */
+   NULL,			/* check access */
+   NULL,			/* type_checker */
+   NULL,			/* fixups */
+   NULL,			/* logger */
+   NULL,			/* header parser */
+   unique_id_child_init,	/* child_init */
+   NULL,			/* child_exit */
+   gen_unique_id		/* post_read_request */
+};




Mime
View raw message