summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwrowe <wrowe@13f79535-47bb-0310-9956-ffa450edef68>2002-07-17 04:11:33 +0000
committerwrowe <wrowe@13f79535-47bb-0310-9956-ffa450edef68>2002-07-17 04:11:33 +0000
commitdbd139a01fc43f70a766835e3f409136aa829d58 (patch)
tree79a6e6948b869bd45455088e53875f3e8073e733
parentdd5959c6435be7958a451e64696f13ba81441dd8 (diff)
downloadlibapr-util-dbd139a01fc43f70a766835e3f409136aa829d58.tar.gz
Move UUID. Not the simplest thing in the world. Note that almost
all the remaining getuuid.c source should be made generic. I just grabbed what my compiler tripped over. git-svn-id: http://svn.apache.org/repos/asf/apr/apr-util/trunk@58692 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--aprutil.dsp12
-rw-r--r--crypto/Makefile.in2
-rw-r--r--crypto/getuuid.c242
-rw-r--r--crypto/uuid.c134
-rw-r--r--include/apr_uuid.h114
-rw-r--r--libaprutil.dsp12
-rw-r--r--test/Makefile.in8
-rw-r--r--test/testuuid.c96
8 files changed, 618 insertions, 2 deletions
diff --git a/aprutil.dsp b/aprutil.dsp
index 0ff03b57..46ef933a 100644
--- a/aprutil.dsp
+++ b/aprutil.dsp
@@ -155,6 +155,14 @@ SOURCE=.\crypto\apr_md5.c
SOURCE=.\crypto\apr_sha1.c
# End Source File
+# Begin Source File
+
+SOURCE=.\crypto\getuuid.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\crypto\uuid.c
+# End Source File
# End Group
# Begin Group "dbm"
@@ -499,6 +507,10 @@ SOURCE=.\include\apr_uri.h
# End Source File
# Begin Source File
+SOURCE=.\include\apr_uuid.h
+# End Source File
+# Begin Source File
+
SOURCE=.\include\apr_xml.h
# End Source File
# Begin Source File
diff --git a/crypto/Makefile.in b/crypto/Makefile.in
index 33af57b8..74f5064b 100644
--- a/crypto/Makefile.in
+++ b/crypto/Makefile.in
@@ -2,7 +2,7 @@ VPATH = @srcdir@
INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@
-TARGETS = apr_sha1.lo apr_md4.lo apr_md5.lo
+TARGETS = apr_sha1.lo apr_md4.lo apr_md5.lo uuid.lo getuuid.lo
# bring in rules.mk for standard functionality
@INCLUDE_RULES@
diff --git a/crypto/getuuid.c b/crypto/getuuid.c
new file mode 100644
index 00000000..09fc19e9
--- /dev/null
+++ b/crypto/getuuid.c
@@ -0,0 +1,242 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/*
+ * This attempts to generate V1 UUIDs according to the Internet Draft
+ * located at http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
+ */
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h> /* for getpid, gethostname */
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h> /* for rand, srand */
+#endif
+
+#include "apr.h"
+#include "apr_uuid.h"
+#include "apr_md5.h"
+#include "apr_general.h"
+#include "apr_portable.h"
+
+
+#if APR_HAVE_STRING_H
+#include <string.h>
+#endif
+#if APR_HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if APR_HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if APR_HAVE_SYS_TIME_H
+#include <sys/time.h> /* for gettimeofday */
+#endif
+
+#define NODE_LENGTH 6
+
+static int uuid_state_seqnum;
+static unsigned char uuid_state_node[NODE_LENGTH] = { 0 };
+
+
+static void get_random_info(unsigned char node[NODE_LENGTH])
+{
+#if APR_HAS_RANDOM
+
+ (void) apr_generate_random_bytes(node, NODE_LENGTH);
+
+#else
+
+ unsigned char seed[MD5_DIGESTSIZE];
+ apr_md5_ctx_t c;
+
+ /* ### probably should revise some of this to be a bit more portable */
+
+ /* Leach & Salz use Linux-specific struct sysinfo;
+ * replace with pid/tid for portability (in the spirit of mod_unique_id) */
+ struct {
+ /* Add thread id here, if applicable, when we get to pthread or apr */
+ pid_t pid;
+#ifdef NETWARE
+ apr_uint64_t t;
+#else
+ struct timeval t;
+#endif
+ char hostname[257];
+
+ } r;
+
+ apr_md5_init(&c);
+#ifdef NETWARE
+ r.pid = NXThreadGetId();
+ NXGetTime(NX_SINCE_BOOT, NX_USECONDS, &(r.t));
+#else
+ r.pid = getpid();
+ gettimeofday(&r.t, (struct timezone *)0);
+#endif
+ gethostname(r.hostname, 256);
+ apr_md5_update(&c, (const unsigned char *)&r, sizeof(r));
+ apr_md5_final(seed, &c);
+
+ memcpy(node, seed, NODE_LENGTH); /* use a subset of the seed bytes */
+#endif
+}
+
+/* This implementation generates a random node ID instead of a
+ system-dependent call to get IEEE node ID. This is also more secure:
+ we aren't passing out our MAC address.
+*/
+static void get_pseudo_node_identifier(unsigned char *node)
+{
+ get_random_info(node);
+ node[0] |= 0x80; /* this designates a random node ID */
+}
+
+static void get_system_time(apr_uint64_t *uuid_time)
+{
+ /* ### fix this call to be more portable? */
+ *uuid_time = apr_time_now();
+
+ /* Offset between UUID formatted times and Unix formatted times.
+ UUID UTC base time is October 15, 1582.
+ Unix base time is January 1, 1970. */
+ *uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000);
+}
+
+/* true_random -- generate a crypto-quality random number. */
+static int true_random(void)
+{
+ apr_uint64_t time_now;
+
+#if APR_HAS_RANDOM
+ unsigned char buf[2];
+
+ if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) {
+ return (buf[0] << 8) | buf[1];
+ }
+#endif
+
+ /* crap. this isn't crypto quality, but it will be Good Enough */
+
+ get_system_time(&time_now);
+ srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff));
+
+ return rand() & 0x0FFFF;
+}
+
+static void init_state(void)
+{
+ uuid_state_seqnum = true_random();
+ get_pseudo_node_identifier(uuid_state_node);
+}
+
+static void get_current_time(apr_uint64_t *timestamp)
+{
+ /* ### this needs to be made thread-safe! */
+
+ apr_time_t time_now;
+ static apr_interval_time_t time_last = 0;
+ static apr_interval_time_t fudge = 0;
+
+ time_now = apr_time_now();
+
+ /* if clock reading changed since last UUID generated... */
+ if (time_last != time_now) {
+ /* The clock reading has changed since the last UUID was generated.
+ Reset the fudge factor. if we are generating them too fast, then
+ the fudge may need to be reset to something greater than zero. */
+ if (time_last + fudge > time_now)
+ fudge = time_last + fudge - time_now + 1;
+ else
+ fudge = 0;
+ time_last = time_now;
+ }
+ else {
+ /* We generated two really fast. Bump the fudge factor. */
+ ++fudge;
+ }
+
+ *timestamp = time_now + fudge;
+}
+
+APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid)
+{
+ apr_uint64_t timestamp;
+ unsigned char *d = uuid->data;
+
+#if APR_HAS_OS_UUID
+ if (apr_os_uuid_get(d) == APR_SUCCESS) {
+ return;
+ }
+#endif /* !APR_HAS_OS_UUID */
+
+ if (!uuid_state_node[0])
+ init_state();
+
+ get_current_time(&timestamp);
+
+ d[0] = (unsigned char)timestamp;
+ d[1] = (unsigned char)(timestamp >> 8);
+ d[2] = (unsigned char)(timestamp >> 16);
+ d[3] = (unsigned char)(timestamp >> 24);
+ d[4] = (unsigned char)(timestamp >> 32);
+ d[5] = (unsigned char)(timestamp >> 40);
+ d[6] = (unsigned char)(timestamp >> 48);
+ d[7] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x10);
+
+ d[8] = (unsigned char)(((uuid_state_seqnum >> 8) & 0x3F) | 0x80);
+ d[9] = (unsigned char)uuid_state_seqnum;
+
+ memcpy(&d[10], uuid_state_node, NODE_LENGTH);
+}
diff --git a/crypto/uuid.c b/crypto/uuid.c
new file mode 100644
index 00000000..b23f0bbd
--- /dev/null
+++ b/crypto/uuid.c
@@ -0,0 +1,134 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+#include <stdio.h> /* for sprintf */
+
+#include "apr.h"
+#include "apr_uuid.h"
+#include "apr_errno.h"
+#include "apr_lib.h"
+
+
+APU_DECLARE(void) apr_uuid_format(char *buffer, const apr_uuid_t *uuid)
+{
+ const unsigned char *d = uuid->data;
+
+ sprintf(buffer,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
+ d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+}
+
+/* convert a pair of hex digits to an integer value [0,255] */
+static unsigned char parse_hexpair(const char *s)
+{
+ int result;
+ int temp;
+
+ result = s[0] - '0';
+ if (result > 48)
+ result = (result - 39) << 4;
+ else if (result > 16)
+ result = (result - 7) << 4;
+ else
+ result = result << 4;
+
+ temp = s[1] - '0';
+ if (temp > 48)
+ result |= temp - 39;
+ else if (temp > 16)
+ result |= temp - 7;
+ else
+ result |= temp;
+
+ return (unsigned char)result;
+}
+
+APU_DECLARE(apr_status_t) apr_uuid_parse(apr_uuid_t *uuid,
+ const char *uuid_str)
+{
+ int i;
+ unsigned char *d = uuid->data;
+
+ for (i = 0; i < 36; ++i) {
+ char c = uuid_str[i];
+ if (!apr_isxdigit(c) &&
+ !(c == '-' && (i == 8 || i == 13 || i == 18 || i == 23)))
+ /* ### need a better value */
+ return APR_BADARG;
+ }
+ if (uuid_str[36] != '\0') {
+ /* ### need a better value */
+ return APR_BADARG;
+ }
+
+ d[0] = parse_hexpair(&uuid_str[0]);
+ d[1] = parse_hexpair(&uuid_str[2]);
+ d[2] = parse_hexpair(&uuid_str[4]);
+ d[3] = parse_hexpair(&uuid_str[6]);
+
+ d[4] = parse_hexpair(&uuid_str[9]);
+ d[5] = parse_hexpair(&uuid_str[11]);
+
+ d[6] = parse_hexpair(&uuid_str[14]);
+ d[7] = parse_hexpair(&uuid_str[16]);
+
+ d[8] = parse_hexpair(&uuid_str[19]);
+ d[9] = parse_hexpair(&uuid_str[21]);
+
+ for (i = 6; i--;)
+ d[10 + i] = parse_hexpair(&uuid_str[i*2+24]);
+
+ return APR_SUCCESS;
+}
diff --git a/include/apr_uuid.h b/include/apr_uuid.h
new file mode 100644
index 00000000..1f60b3fd
--- /dev/null
+++ b/include/apr_uuid.h
@@ -0,0 +1,114 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * @file apr_uuid.h
+ * @brief APR UUID library
+ */
+#ifndef APR_UUID_H
+#define APR_UUID_H
+
+#include "apu.h"
+#include "apr_errno.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup APR_UUID UUID Handling
+ * @ingroup APR
+ * @{
+ */
+
+/**
+ * we represent a UUID as a block of 16 bytes.
+ */
+
+typedef struct {
+ unsigned char data[16]; /**< the actual UUID */
+} apr_uuid_t;
+
+/** UUIDs are formatted as: 00112233-4455-6677-8899-AABBCCDDEEFF */
+#define APR_UUID_FORMATTED_LENGTH 36
+
+
+/**
+ * Generate and return a (new) UUID
+ * @param uuid The resulting UUID
+ */
+APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid);
+
+/**
+ * Format a UUID into a string, following the standard format
+ * @param buffer The buffer to place the formatted UUID string into. It must
+ * be at least APR_UUID_FORMATTED_LENGTH + 1 bytes long to hold
+ * the formatted UUID and a null terminator
+ * @param uuid The UUID to format
+ */
+APU_DECLARE(void) apr_uuid_format(char *buffer, const apr_uuid_t *uuid);
+
+/**
+ * Parse a standard-format string into a UUID
+ * @param uuid The resulting UUID
+ * @param uuid_str The formatted UUID
+ */
+APU_DECLARE(apr_status_t) apr_uuid_parse(apr_uuid_t *uuid, const char *uuid_str);
+
+/** @} */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* APR_UUID_H */
diff --git a/libaprutil.dsp b/libaprutil.dsp
index 3f88aa02..818750dd 100644
--- a/libaprutil.dsp
+++ b/libaprutil.dsp
@@ -161,6 +161,14 @@ SOURCE=.\crypto\apr_md5.c
SOURCE=.\crypto\apr_sha1.c
# End Source File
+# Begin Source File
+
+SOURCE=.\crypto\getuuid.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\crypto\uuid.c
+# End Source File
# End Group
# Begin Group "dbm"
@@ -505,6 +513,10 @@ SOURCE=.\include\apr_uri.h
# End Source File
# Begin Source File
+SOURCE=.\include\apr_uuid.h
+# End Source File
+# Begin Source File
+
SOURCE=.\include\apr_xml.h
# End Source File
# Begin Source File
diff --git a/test/Makefile.in b/test/Makefile.in
index c43157c4..4ed8703f 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -2,7 +2,7 @@ VPATH = @srcdir@
INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@
-PROGRAMS = testdbm testdate testmd4 testmd5 testxml testrmm teststrmatch
+PROGRAMS = testdbm testdate testmd4 testmd5 testxml testrmm teststrmatch testuuid
TARGETS = $(PROGRAMS)
# bring in rules.mk for standard functionality
@@ -45,3 +45,9 @@ teststrmatch_OBJECTS = teststrmatch.lo
teststrmatch_LDADD = ../libaprutil.la
teststrmatch: $(teststrmatch_OBJECTS) $(teststrmatch_LDADD)
$(LINK) $(teststrmatch_OBJECTS) $(teststrmatch_LDADD) $(PROGRAM_DEPENDENCIES)
+
+testuuid_OBJECTS = testuuid.lo
+testuuid_LDADD = ../libaprutil.la
+testuuid: $(testuuid_OBJECTS) $(testuuid_LDADD)
+ $(LINK) $(testuuid_OBJECTS) $(testuuid_LDADD) $(PROGRAM_DEPENDENCIES)
+
diff --git a/test/testuuid.c b/test/testuuid.c
new file mode 100644
index 00000000..8a691d81
--- /dev/null
+++ b/test/testuuid.c
@@ -0,0 +1,96 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_general.h"
+#include "apr_uuid.h"
+
+
+int main(int argc, char **argv)
+{
+ apr_uuid_t uuid;
+ apr_uuid_t uuid2;
+ char buf[APR_UUID_FORMATTED_LENGTH + 1];
+ int retcode = 0;
+
+ apr_initialize();
+ atexit(apr_terminate);
+
+ apr_uuid_get(&uuid);
+ apr_uuid_format(buf, &uuid);
+ printf("UUID: %s\n", buf);
+
+ apr_uuid_parse(&uuid2, buf);
+ if (memcmp(&uuid, &uuid2, sizeof(uuid)) == 0)
+ printf("Parse appears to work.\n");
+ else {
+ printf("ERROR: parse produced a different UUID.\n");
+ retcode = 1;
+ }
+
+ apr_uuid_format(buf, &uuid2);
+ printf("parsed/reformatted UUID: %s\n", buf);
+
+ /* generate two of them quickly */
+ apr_uuid_get(&uuid);
+ apr_uuid_get(&uuid2);
+ apr_uuid_format(buf, &uuid);
+ printf("UUID 1: %s\n", buf);
+ apr_uuid_format(buf, &uuid2);
+ printf("UUID 2: %s\n", buf);
+
+ return retcode;
+}