#include "apr.h"
#include "apr_uuid.h"
#include "apr_md5.h"
#include "apr_general.h"
#include "apr_portable.h"
#if APR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if APR_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#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>
#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[APR_MD5_DIGESTSIZE];
apr_md5_ctx_t c;
struct {
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);
#endif
}
static void get_pseudo_node_identifier(unsigned char *node)
{
get_random_info(node);
node[0] |= 0x01;
}
static void get_system_time(apr_uint64_t *uuid_time)
{
*uuid_time = apr_time_now();
*uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000);
}
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
time_now = apr_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)
{
apr_uint64_t time_now;
static apr_uint64_t time_last = 0;
static apr_uint64_t fudge = 0;
get_system_time(&time_now);
if (time_last != time_now) {
if (time_last + fudge > time_now)
fudge = time_last + fudge - time_now + 1;
else
fudge = 0;
time_last = time_now;
}
else {
++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
if (!uuid_state_node[0])
init_state();
get_current_time(×tamp);
d[3] = (unsigned char)timestamp;
d[2] = (unsigned char)(timestamp >> 8);
d[1] = (unsigned char)(timestamp >> 16);
d[0] = (unsigned char)(timestamp >> 24);
d[5] = (unsigned char)(timestamp >> 32);
d[4] = (unsigned char)(timestamp >> 40);
d[7] = (unsigned char)(timestamp >> 48);
d[6] = (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);
}