|
Packit |
383869 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
383869 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
383869 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
383869 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
383869 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
383869 |
* the License. You may obtain a copy of the License at
|
|
Packit |
383869 |
*
|
|
Packit |
383869 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
383869 |
*
|
|
Packit |
383869 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
383869 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
383869 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
383869 |
* See the License for the specific language governing permissions and
|
|
Packit |
383869 |
* limitations under the License.
|
|
Packit |
383869 |
*/
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/*
|
|
Packit |
383869 |
* This attempts to generate V1 UUIDs according to the Internet Draft
|
|
Packit |
383869 |
* located at http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
|
|
Packit |
383869 |
*/
|
|
Packit |
383869 |
#include "apr.h"
|
|
Packit |
383869 |
#include "apr_uuid.h"
|
|
Packit |
383869 |
#include "apr_md5.h"
|
|
Packit |
383869 |
#include "apr_general.h"
|
|
Packit |
383869 |
#include "apr_portable.h"
|
|
Packit |
383869 |
|
|
Packit |
383869 |
|
|
Packit |
383869 |
#if APR_HAVE_UNISTD_H
|
|
Packit |
383869 |
#include <unistd.h> /* for getpid, gethostname */
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
#if APR_HAVE_STDLIB_H
|
|
Packit |
383869 |
#include <stdlib.h> /* for rand, srand */
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
|
|
Packit |
383869 |
|
|
Packit |
383869 |
#if APR_HAVE_STRING_H
|
|
Packit |
383869 |
#include <string.h>
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
#if APR_HAVE_STRINGS_H
|
|
Packit |
383869 |
#include <strings.h>
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
#if APR_HAVE_NETDB_H
|
|
Packit |
383869 |
#include <netdb.h>
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
#if APR_HAVE_SYS_TIME_H
|
|
Packit |
383869 |
#include <sys/time.h> /* for gettimeofday */
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
|
|
Packit |
383869 |
#define NODE_LENGTH 6
|
|
Packit |
383869 |
|
|
Packit |
383869 |
static int uuid_state_seqnum;
|
|
Packit |
383869 |
static unsigned char uuid_state_node[NODE_LENGTH] = { 0 };
|
|
Packit |
383869 |
|
|
Packit |
383869 |
|
|
Packit |
383869 |
static void get_random_info(unsigned char node[NODE_LENGTH])
|
|
Packit |
383869 |
{
|
|
Packit |
383869 |
#if APR_HAS_RANDOM
|
|
Packit |
383869 |
|
|
Packit |
383869 |
(void) apr_generate_random_bytes(node, NODE_LENGTH);
|
|
Packit |
383869 |
|
|
Packit |
383869 |
#else
|
|
Packit |
383869 |
|
|
Packit |
383869 |
unsigned char seed[APR_MD5_DIGESTSIZE];
|
|
Packit |
383869 |
apr_md5_ctx_t c;
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* ### probably should revise some of this to be a bit more portable */
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* Leach & Salz use Linux-specific struct sysinfo;
|
|
Packit |
383869 |
* replace with pid/tid for portability (in the spirit of mod_unique_id) */
|
|
Packit |
383869 |
struct {
|
|
Packit |
383869 |
/* Add thread id here, if applicable, when we get to pthread or apr */
|
|
Packit |
383869 |
pid_t pid;
|
|
Packit |
383869 |
#ifdef NETWARE
|
|
Packit |
383869 |
apr_uint64_t t;
|
|
Packit |
383869 |
#else
|
|
Packit |
383869 |
struct timeval t;
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
char hostname[257];
|
|
Packit |
383869 |
|
|
Packit |
383869 |
} r;
|
|
Packit |
383869 |
|
|
Packit |
383869 |
apr_md5_init(&c);
|
|
Packit |
383869 |
#ifdef NETWARE
|
|
Packit |
383869 |
r.pid = NXThreadGetId();
|
|
Packit |
383869 |
NXGetTime(NX_SINCE_BOOT, NX_USECONDS, &(r.t));
|
|
Packit |
383869 |
#else
|
|
Packit |
383869 |
r.pid = getpid();
|
|
Packit |
383869 |
gettimeofday(&r.t, (struct timezone *)0);
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
gethostname(r.hostname, 256);
|
|
Packit |
383869 |
apr_md5_update(&c, (const unsigned char *)&r, sizeof(r));
|
|
Packit |
383869 |
apr_md5_final(seed, &c);
|
|
Packit |
383869 |
|
|
Packit |
383869 |
memcpy(node, seed, NODE_LENGTH); /* use a subset of the seed bytes */
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* This implementation generates a random node ID instead of a
|
|
Packit |
383869 |
system-dependent call to get IEEE node ID. This is also more secure:
|
|
Packit |
383869 |
we aren't passing out our MAC address.
|
|
Packit |
383869 |
*/
|
|
Packit |
383869 |
static void get_pseudo_node_identifier(unsigned char *node)
|
|
Packit |
383869 |
{
|
|
Packit |
383869 |
get_random_info(node);
|
|
Packit |
383869 |
node[0] |= 0x01; /* this designates a random multicast node ID */
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
|
|
Packit |
383869 |
static void get_system_time(apr_uint64_t *uuid_time)
|
|
Packit |
383869 |
{
|
|
Packit |
383869 |
/* ### fix this call to be more portable? */
|
|
Packit |
383869 |
*uuid_time = apr_time_now();
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* Offset between UUID formatted times and Unix formatted times.
|
|
Packit |
383869 |
UUID UTC base time is October 15, 1582.
|
|
Packit |
383869 |
Unix base time is January 1, 1970. */
|
|
Packit |
383869 |
*uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000);
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* true_random -- generate a crypto-quality random number. */
|
|
Packit |
383869 |
static int true_random(void)
|
|
Packit |
383869 |
{
|
|
Packit |
383869 |
apr_uint64_t time_now;
|
|
Packit |
383869 |
|
|
Packit |
383869 |
#if APR_HAS_RANDOM
|
|
Packit |
383869 |
unsigned char buf[2];
|
|
Packit |
383869 |
|
|
Packit |
383869 |
if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) {
|
|
Packit |
383869 |
return (buf[0] << 8) | buf[1];
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
#endif
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* crap. this isn't crypto quality, but it will be Good Enough */
|
|
Packit |
383869 |
|
|
Packit |
383869 |
time_now = apr_time_now();
|
|
Packit |
383869 |
srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff));
|
|
Packit |
383869 |
|
|
Packit |
383869 |
return rand() & 0x0FFFF;
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
|
|
Packit |
383869 |
static void init_state(void)
|
|
Packit |
383869 |
{
|
|
Packit |
383869 |
uuid_state_seqnum = true_random();
|
|
Packit |
383869 |
get_pseudo_node_identifier(uuid_state_node);
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
|
|
Packit |
383869 |
static void get_current_time(apr_uint64_t *timestamp)
|
|
Packit |
383869 |
{
|
|
Packit |
383869 |
/* ### this needs to be made thread-safe! */
|
|
Packit |
383869 |
|
|
Packit |
383869 |
apr_uint64_t time_now;
|
|
Packit |
383869 |
static apr_uint64_t time_last = 0;
|
|
Packit |
383869 |
static apr_uint64_t fudge = 0;
|
|
Packit |
383869 |
|
|
Packit |
383869 |
get_system_time(&time_now);
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* if clock reading changed since last UUID generated... */
|
|
Packit |
383869 |
if (time_last != time_now) {
|
|
Packit |
383869 |
/* The clock reading has changed since the last UUID was generated.
|
|
Packit |
383869 |
Reset the fudge factor. if we are generating them too fast, then
|
|
Packit |
383869 |
the fudge may need to be reset to something greater than zero. */
|
|
Packit |
383869 |
if (time_last + fudge > time_now)
|
|
Packit |
383869 |
fudge = time_last + fudge - time_now + 1;
|
|
Packit |
383869 |
else
|
|
Packit |
383869 |
fudge = 0;
|
|
Packit |
383869 |
time_last = time_now;
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
else {
|
|
Packit |
383869 |
/* We generated two really fast. Bump the fudge factor. */
|
|
Packit |
383869 |
++fudge;
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
|
|
Packit |
383869 |
*timestamp = time_now + fudge;
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
|
|
Packit |
383869 |
APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid)
|
|
Packit |
383869 |
{
|
|
Packit |
383869 |
apr_uint64_t timestamp;
|
|
Packit |
383869 |
unsigned char *d = uuid->data;
|
|
Packit |
383869 |
|
|
Packit |
383869 |
#if APR_HAS_OS_UUID
|
|
Packit |
383869 |
if (apr_os_uuid_get(d) == APR_SUCCESS) {
|
|
Packit |
383869 |
return;
|
|
Packit |
383869 |
}
|
|
Packit |
383869 |
#endif /* !APR_HAS_OS_UUID */
|
|
Packit |
383869 |
|
|
Packit |
383869 |
if (!uuid_state_node[0])
|
|
Packit |
383869 |
init_state();
|
|
Packit |
383869 |
|
|
Packit |
383869 |
get_current_time(×tamp);
|
|
Packit |
383869 |
|
|
Packit |
383869 |
/* time_low, uint32 */
|
|
Packit |
383869 |
d[3] = (unsigned char)timestamp;
|
|
Packit |
383869 |
d[2] = (unsigned char)(timestamp >> 8);
|
|
Packit |
383869 |
d[1] = (unsigned char)(timestamp >> 16);
|
|
Packit |
383869 |
d[0] = (unsigned char)(timestamp >> 24);
|
|
Packit |
383869 |
/* time_mid, uint16 */
|
|
Packit |
383869 |
d[5] = (unsigned char)(timestamp >> 32);
|
|
Packit |
383869 |
d[4] = (unsigned char)(timestamp >> 40);
|
|
Packit |
383869 |
/* time_hi_and_version, uint16 */
|
|
Packit |
383869 |
d[7] = (unsigned char)(timestamp >> 48);
|
|
Packit |
383869 |
d[6] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x10);
|
|
Packit |
383869 |
/* clock_seq_hi_and_reserved, uint8 */
|
|
Packit |
383869 |
d[8] = (unsigned char)(((uuid_state_seqnum >> 8) & 0x3F) | 0x80);
|
|
Packit |
383869 |
/* clock_seq_low, uint8 */
|
|
Packit |
383869 |
d[9] = (unsigned char)uuid_state_seqnum;
|
|
Packit |
383869 |
/* node, byte[6] */
|
|
Packit |
383869 |
memcpy(&d[10], uuid_state_node, NODE_LENGTH);
|
|
Packit |
383869 |
}
|