1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
18
* This attempts to generate V1 UUIDs according to the Internet Draft
19
* located at http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
24
#include "apr_general.h"
25
#include "apr_portable.h"
29
#include <unistd.h> /* for getpid, gethostname */
32
#include <stdlib.h> /* for rand, srand */
39
#if APR_HAVE_STRINGS_H
45
#if APR_HAVE_SYS_TIME_H
46
#include <sys/time.h> /* for gettimeofday */
51
static int uuid_state_seqnum;
52
static unsigned char uuid_state_node[NODE_LENGTH] = { 0 };
55
static void get_random_info(unsigned char node[NODE_LENGTH])
59
(void) apr_generate_random_bytes(node, NODE_LENGTH);
63
unsigned char seed[APR_MD5_DIGESTSIZE];
66
/* ### probably should revise some of this to be a bit more portable */
68
/* Leach & Salz use Linux-specific struct sysinfo;
69
* replace with pid/tid for portability (in the spirit of mod_unique_id) */
71
/* Add thread id here, if applicable, when we get to pthread or apr */
84
r.pid = NXThreadGetId();
85
NXGetTime(NX_SINCE_BOOT, NX_USECONDS, &(r.t));
88
gettimeofday(&r.t, (struct timezone *)0);
90
gethostname(r.hostname, 256);
91
apr_md5_update(&c, (const unsigned char *)&r, sizeof(r));
92
apr_md5_final(seed, &c);
94
memcpy(node, seed, NODE_LENGTH); /* use a subset of the seed bytes */
98
/* This implementation generates a random node ID instead of a
99
system-dependent call to get IEEE node ID. This is also more secure:
100
we aren't passing out our MAC address.
102
static void get_pseudo_node_identifier(unsigned char *node)
104
get_random_info(node);
105
node[0] |= 0x01; /* this designates a random node ID */
108
static void get_system_time(apr_uint64_t *uuid_time)
110
/* ### fix this call to be more portable? */
111
*uuid_time = apr_time_now();
113
/* Offset between UUID formatted times and Unix formatted times.
114
UUID UTC base time is October 15, 1582.
115
Unix base time is January 1, 1970. */
116
*uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000);
119
/* true_random -- generate a crypto-quality random number. */
120
static int true_random(void)
122
apr_uint64_t time_now;
125
unsigned char buf[2];
127
if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) {
128
return (buf[0] << 8) | buf[1];
132
/* crap. this isn't crypto quality, but it will be Good Enough */
134
get_system_time(&time_now);
135
srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff));
137
return rand() & 0x0FFFF;
140
static void init_state(void)
142
uuid_state_seqnum = true_random();
143
get_pseudo_node_identifier(uuid_state_node);
146
static void get_current_time(apr_uint64_t *timestamp)
148
/* ### this needs to be made thread-safe! */
151
static apr_interval_time_t time_last = 0;
152
static apr_interval_time_t fudge = 0;
154
time_now = apr_time_now();
156
/* if clock reading changed since last UUID generated... */
157
if (time_last != time_now) {
158
/* The clock reading has changed since the last UUID was generated.
159
Reset the fudge factor. if we are generating them too fast, then
160
the fudge may need to be reset to something greater than zero. */
161
if (time_last + fudge > time_now)
162
fudge = time_last + fudge - time_now + 1;
165
time_last = time_now;
168
/* We generated two really fast. Bump the fudge factor. */
172
*timestamp = time_now + fudge;
175
APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid)
177
apr_uint64_t timestamp;
178
unsigned char *d = uuid->data;
181
if (apr_os_uuid_get(d) == APR_SUCCESS) {
184
#endif /* !APR_HAS_OS_UUID */
186
if (!uuid_state_node[0])
189
get_current_time(×tamp);
191
d[0] = (unsigned char)timestamp;
192
d[1] = (unsigned char)(timestamp >> 8);
193
d[2] = (unsigned char)(timestamp >> 16);
194
d[3] = (unsigned char)(timestamp >> 24);
195
d[4] = (unsigned char)(timestamp >> 32);
196
d[5] = (unsigned char)(timestamp >> 40);
197
d[6] = (unsigned char)(timestamp >> 48);
198
d[7] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x10);
200
d[8] = (unsigned char)(((uuid_state_seqnum >> 8) & 0x3F) | 0x80);
201
d[9] = (unsigned char)uuid_state_seqnum;
203
memcpy(&d[10], uuid_state_node, NODE_LENGTH);