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(×tamp); 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