1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter/*
18251876Speter * This attempts to generate V1 UUIDs according to the Internet Draft
19251876Speter * located at http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
20251876Speter */
21251876Speter#include "apr.h"
22251876Speter#include "apr_uuid.h"
23251876Speter#include "apr_md5.h"
24251876Speter#include "apr_general.h"
25251876Speter#include "apr_portable.h"
26251876Speter
27251876Speter
28251876Speter#if APR_HAVE_UNISTD_H
29251876Speter#include <unistd.h>     /* for getpid, gethostname */
30251876Speter#endif
31251876Speter#if APR_HAVE_STDLIB_H
32251876Speter#include <stdlib.h>     /* for rand, srand */
33251876Speter#endif
34251876Speter
35251876Speter
36251876Speter#if APR_HAVE_STRING_H
37251876Speter#include <string.h>
38251876Speter#endif
39251876Speter#if APR_HAVE_STRINGS_H
40251876Speter#include <strings.h>
41251876Speter#endif
42251876Speter#if APR_HAVE_NETDB_H
43251876Speter#include <netdb.h>
44251876Speter#endif
45251876Speter#if APR_HAVE_SYS_TIME_H
46251876Speter#include <sys/time.h>   /* for gettimeofday */
47251876Speter#endif
48251876Speter
49251876Speter#define NODE_LENGTH 6
50251876Speter
51251876Speterstatic int uuid_state_seqnum;
52251876Speterstatic unsigned char uuid_state_node[NODE_LENGTH] = { 0 };
53251876Speter
54251876Speter
55251876Speterstatic void get_random_info(unsigned char node[NODE_LENGTH])
56251876Speter{
57251876Speter#if APR_HAS_RANDOM
58251876Speter
59251876Speter    (void) apr_generate_random_bytes(node, NODE_LENGTH);
60251876Speter
61251876Speter#else
62251876Speter
63251876Speter    unsigned char seed[APR_MD5_DIGESTSIZE];
64251876Speter    apr_md5_ctx_t c;
65251876Speter
66251876Speter    /* ### probably should revise some of this to be a bit more portable */
67251876Speter
68251876Speter    /* Leach & Salz use Linux-specific struct sysinfo;
69251876Speter     * replace with pid/tid for portability (in the spirit of mod_unique_id) */
70251876Speter    struct {
71251876Speter	/* Add thread id here, if applicable, when we get to pthread or apr */
72251876Speter        pid_t pid;
73251876Speter#ifdef NETWARE
74251876Speter        apr_uint64_t t;
75251876Speter#else
76251876Speter        struct timeval t;
77251876Speter#endif
78251876Speter        char hostname[257];
79251876Speter
80251876Speter    } r;
81251876Speter
82251876Speter    apr_md5_init(&c);
83251876Speter#ifdef NETWARE
84251876Speter    r.pid = NXThreadGetId();
85251876Speter    NXGetTime(NX_SINCE_BOOT, NX_USECONDS, &(r.t));
86251876Speter#else
87251876Speter    r.pid = getpid();
88251876Speter    gettimeofday(&r.t, (struct timezone *)0);
89251876Speter#endif
90251876Speter    gethostname(r.hostname, 256);
91251876Speter    apr_md5_update(&c, (const unsigned char *)&r, sizeof(r));
92251876Speter    apr_md5_final(seed, &c);
93251876Speter
94251876Speter    memcpy(node, seed, NODE_LENGTH);    /* use a subset of the seed bytes */
95251876Speter#endif
96251876Speter}
97251876Speter
98251876Speter/* This implementation generates a random node ID instead of a
99251876Speter   system-dependent call to get IEEE node ID. This is also more secure:
100251876Speter   we aren't passing out our MAC address.
101251876Speter*/
102251876Speterstatic void get_pseudo_node_identifier(unsigned char *node)
103251876Speter{
104251876Speter    get_random_info(node);
105251876Speter    node[0] |= 0x01;                    /* this designates a random multicast node ID */
106251876Speter}
107251876Speter
108251876Speterstatic void get_system_time(apr_uint64_t *uuid_time)
109251876Speter{
110251876Speter    /* ### fix this call to be more portable? */
111251876Speter    *uuid_time = apr_time_now();
112251876Speter
113251876Speter    /* Offset between UUID formatted times and Unix formatted times.
114251876Speter       UUID UTC base time is October 15, 1582.
115251876Speter       Unix base time is January 1, 1970.      */
116251876Speter    *uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000);
117251876Speter}
118251876Speter
119251876Speter/* true_random -- generate a crypto-quality random number. */
120251876Speterstatic int true_random(void)
121251876Speter{
122251876Speter    apr_uint64_t time_now;
123251876Speter
124251876Speter#if APR_HAS_RANDOM
125251876Speter    unsigned char buf[2];
126251876Speter
127251876Speter    if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) {
128251876Speter        return (buf[0] << 8) | buf[1];
129251876Speter    }
130251876Speter#endif
131251876Speter
132251876Speter    /* crap. this isn't crypto quality, but it will be Good Enough */
133251876Speter
134251876Speter    time_now = apr_time_now();
135251876Speter    srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff));
136251876Speter
137251876Speter    return rand() & 0x0FFFF;
138251876Speter}
139251876Speter
140251876Speterstatic void init_state(void)
141251876Speter{
142251876Speter    uuid_state_seqnum = true_random();
143251876Speter    get_pseudo_node_identifier(uuid_state_node);
144251876Speter}
145251876Speter
146251876Speterstatic void get_current_time(apr_uint64_t *timestamp)
147251876Speter{
148251876Speter    /* ### this needs to be made thread-safe! */
149251876Speter
150251876Speter    apr_uint64_t time_now;
151251876Speter    static apr_uint64_t time_last = 0;
152251876Speter    static apr_uint64_t fudge = 0;
153251876Speter
154251876Speter    get_system_time(&time_now);
155251876Speter
156251876Speter    /* if clock reading changed since last UUID generated... */
157251876Speter    if (time_last != time_now) {
158251876Speter        /* The clock reading has changed since the last UUID was generated.
159251876Speter           Reset the fudge factor. if we are generating them too fast, then
160251876Speter           the fudge may need to be reset to something greater than zero. */
161251876Speter        if (time_last + fudge > time_now)
162251876Speter            fudge = time_last + fudge - time_now + 1;
163251876Speter        else
164251876Speter            fudge = 0;
165251876Speter        time_last = time_now;
166251876Speter    }
167251876Speter    else {
168251876Speter        /* We generated two really fast. Bump the fudge factor. */
169251876Speter        ++fudge;
170251876Speter    }
171251876Speter
172251876Speter    *timestamp = time_now + fudge;
173251876Speter}
174251876Speter
175251876SpeterAPU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid)
176251876Speter{
177251876Speter    apr_uint64_t timestamp;
178251876Speter    unsigned char *d = uuid->data;
179251876Speter
180251876Speter#if APR_HAS_OS_UUID
181251876Speter    if (apr_os_uuid_get(d) == APR_SUCCESS) {
182251876Speter        return;
183251876Speter    }
184251876Speter#endif /* !APR_HAS_OS_UUID */
185251876Speter
186251876Speter    if (!uuid_state_node[0])
187251876Speter        init_state();
188251876Speter
189251876Speter    get_current_time(&timestamp);
190251876Speter
191251876Speter    /* time_low, uint32 */
192251876Speter    d[3] = (unsigned char)timestamp;
193251876Speter    d[2] = (unsigned char)(timestamp >> 8);
194251876Speter    d[1] = (unsigned char)(timestamp >> 16);
195251876Speter    d[0] = (unsigned char)(timestamp >> 24);
196251876Speter    /* time_mid, uint16 */
197251876Speter    d[5] = (unsigned char)(timestamp >> 32);
198251876Speter    d[4] = (unsigned char)(timestamp >> 40);
199251876Speter    /* time_hi_and_version, uint16 */
200251876Speter    d[7] = (unsigned char)(timestamp >> 48);
201251876Speter    d[6] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x10);
202251876Speter    /* clock_seq_hi_and_reserved, uint8 */
203251876Speter    d[8] = (unsigned char)(((uuid_state_seqnum >> 8) & 0x3F) | 0x80);
204251876Speter    /* clock_seq_low, uint8 */
205251876Speter    d[9] = (unsigned char)uuid_state_seqnum;
206251876Speter    /* node, byte[6] */
207251876Speter    memcpy(&d[10], uuid_state_node, NODE_LENGTH);
208251876Speter}
209