diff options
Diffstat (limited to 'src/net_uuid.c')
-rw-r--r-- | src/net_uuid.c | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/src/net_uuid.c b/src/net_uuid.c new file mode 100644 index 0000000..8701120 --- /dev/null +++ b/src/net_uuid.c @@ -0,0 +1,357 @@ +/* what follows is a somewhat stripped-down version of the sample + implementation of UUID generation from RFC 4122. */ + +/* +** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & +** Digital Equipment Corporation, Maynard, Mass. +** Copyright (c) 1998 Microsoft. +** To anyone who acknowledges that this file is provided "AS IS" +** without any express or implied warranty: permission to use, copy, +** modify, and distribute this file for any purpose is hereby +** granted without fee, provided that the above copyright notices and +** this notice appears in all source code copies, and that none of +** the names of Open Software Foundation, Inc., Hewlett-Packard +** Company, Microsoft, or Digital Equipment Corporation be used in +** advertising or publicity pertaining to distribution of the software +** without specific, written prior permission. Neither Open Software +** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital +** Equipment Corporation makes any representations about the +** suitability of this software for any purpose. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> + +#if defined(HAVE_INTTYPES_H) +#include <inttypes.h> +#endif + +/* set the following to the number of 100ns ticks of the actual + resolution of your system's clock */ +#define UUIDS_PER_TICK 1024 + +#ifdef WIN32 +#include <windows.h> +#include "missing\stdint.h" +#define snprintf _snprintf +#else + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#else +# if HAVE_STDINT_H +# include <stdint.h> +# endif +#endif + +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#if HAVE_SYS_SYSINFO_H +#include <sys/sysinfo.h> +#endif + +#endif + +/* system dependent call to get the current system time. Returned as + 100ns ticks since UUID epoch, but resolution may be less than + 100ns. */ + +#ifdef WIN32 +#define I64(C) C +#else +#define I64(C) C##LL +#endif + +typedef uint64_t uuid_time_t; + +typedef struct { + char nodeID[6]; +} uuid_node_t; + +#undef uuid_t +typedef struct { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +} uuid_t; + +/* some forward declarations. kind of wimpy to do that but heck, we + are all friends here right? raj 20081024 */ +static uint16_t true_random(void); + + + +#ifdef WIN32 + +static void get_system_time(uuid_time_t *uuid_time) +{ + ULARGE_INTEGER time; + + /* NT keeps time in FILETIME format which is 100ns ticks since + Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582. + The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec) + + 18 years and 5 leap days. */ + GetSystemTimeAsFileTime((FILETIME *)&time); + time.QuadPart += + + (unsigned __int64) (1000*1000*10) // seconds + * (unsigned __int64) (60 * 60 * 24) // days + * (unsigned __int64) (17+30+31+365*18+5); // # of days + *uuid_time = time.QuadPart; +} + +/* Sample code, not for use in production; see RFC 1750 */ +static void get_random_info(char seed[16]) +{ + uint16_t myrand; + int i; + + i = 0; + do { + myrand = true_random(); + seed[i++] = myrand & 0xff; + seed[i++] = myrand >> 8; + } while (i < 14); + +} + +#else + +static void get_system_time(uuid_time_t *uuid_time) +{ + struct timeval tp; + + gettimeofday(&tp, (struct timezone *)0); + + /* Offset between UUID formatted times and Unix formatted times. + UUID UTC base time is October 15, 1582. + Unix base time is January 1, 1970.*/ + *uuid_time = ((uint64_t)tp.tv_sec * 10000000) + + ((uint64_t)tp.tv_usec * 10) + + I64(0x01B21DD213814000); +} + +/* Sample code, not for use in production; see RFC 1750 */ +static void get_random_info(char seed[16]) +{ + int fd; + uint16_t myrand; + int i; + + /* we aren't all that picky, and we would rather not block so we + will use urandom */ + fd = open("/dev/urandom", O_RDONLY); + + if (fd != -1) { + read(fd, seed, 16); + close(fd); + return; + } + + /* ok, now what? */ + + i = 0; + do { + myrand = true_random(); + seed[i++] = myrand & 0xff; + seed[i++] = myrand >> 8; + } while (i < 14); + +} + +#endif + + +/* true_random -- generate a crypto-quality random number. +**This sample doesn't do that.** */ +static uint16_t true_random(void) +{ + static int inited = 0; + uuid_time_t time_now; + + if (!inited) { + get_system_time(&time_now); + time_now = time_now / UUIDS_PER_TICK; + srand((unsigned int) + (((time_now >> 32) ^ time_now) & 0xffffffff)); + inited = 1; + } + + return (uint16_t)rand(); +} + +/* puid -- print a UUID */ +void puid(uuid_t u) +{ + int i; + + printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid, + u.time_hi_and_version, u.clock_seq_hi_and_reserved, + u.clock_seq_low); + for (i = 0; i < 6; i++) + printf("%2.2x", u.node[i]); + printf("\n"); +} + +/* snpuid -- print a UUID in the supplied buffer */ +void snpuid(char *str, size_t size, uuid_t u) { + int i; + char *tmp = str; + + if (size < 38) { + snprintf(tmp,size,"%s","uuid string too small"); + return; + } + + /* perhaps this is a trifle optimistic but what the heck */ + sprintf(tmp, + "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", + u.time_low, + u.time_mid, + u.time_hi_and_version, + u.clock_seq_hi_and_reserved, + u.clock_seq_low); + tmp += 24; + for (i = 0; i < 6; i++) { + sprintf(tmp,"%2.2x", u.node[i]); + tmp += 2; + } + *tmp = 0; + +} + +/* get-current_time -- get time as 60-bit 100ns ticks since UUID epoch. + Compensate for the fact that real clock resolution is + less than 100ns. */ +static void get_current_time(uuid_time_t *timestamp) +{ + static int inited = 0; + static uuid_time_t time_last; + static uint16_t uuids_this_tick; + uuid_time_t time_now; + + if (!inited) { + get_system_time(&time_now); + uuids_this_tick = UUIDS_PER_TICK; + inited = 1; + } + + for ( ; ; ) { + get_system_time(&time_now); + + /* if clock reading changed since last UUID generated, */ + if (time_last != time_now) { + /* reset count of uuids gen'd with this clock reading */ + uuids_this_tick = 0; + time_last = time_now; + break; + } + if (uuids_this_tick < UUIDS_PER_TICK) { + uuids_this_tick++; + break; + } + /* going too fast for our clock; spin */ + } + /* add the count of uuids to low order bits of the clock reading */ + *timestamp = time_now + uuids_this_tick; +} + + +/* system dependent call to get IEEE node ID. + This sample implementation generates a random node ID. */ +/* netperf mod - don't bother trying to read or write the nodeid */ +static void get_ieee_node_identifier(uuid_node_t *node) +{ + static int inited = 0; + static uuid_node_t saved_node; + char seed[16]; + + if (!inited) { + get_random_info(seed); + seed[0] |= 0x01; + memcpy(&saved_node, seed, sizeof saved_node); + } + inited = 1; + + *node = saved_node; +} + + +/* format_uuid_v1 -- make a UUID from the timestamp, clockseq, + and node ID */ +static void format_uuid_v1(uuid_t* uuid, uint16_t clock_seq, + uuid_time_t timestamp, uuid_node_t node) +{ + /* Construct a version 1 uuid with the information we've gathered + plus a few constants. */ + uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); + uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); + uuid->time_hi_and_version = + (unsigned short)((timestamp >> 48) & 0x0FFF); + uuid->time_hi_and_version |= (1 << 12); + uuid->clock_seq_low = clock_seq & 0xFF; + uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8; + uuid->clock_seq_hi_and_reserved |= 0x80; + memcpy(&uuid->node, &node, sizeof uuid->node); +} + +/* uuid_create -- generator a UUID */ +int uuid_create(uuid_t *uuid) +{ + uuid_time_t timestamp; + uint16_t clockseq; + uuid_node_t node; + + /* get time, node ID, saved state from non-volatile storage */ + get_current_time(×tamp); + get_ieee_node_identifier(&node); + + /* for us clockseq is always to be random as we have no state */ + clockseq = true_random(); + + /* stuff fields into the UUID */ + format_uuid_v1(uuid, clockseq, timestamp, node); + return 1; +} + +void get_uuid_string(char *uuid_str, size_t size) { + uuid_t u; + + uuid_create(&u); + snpuid(uuid_str,size,u); + + return; +} + +#ifdef NETPERF_STANDALONE_DEBUG + +int +main(int argc, char *argv[]) +{ + uuid_t u; + char uuid_str[38]; +#if 0 + uuid_create(&u); + printf("uuid_create(): "); puid(u); + snpuid(uuid_str,sizeof(uuid_str),u); + printf("\nas a string %s\n",uuid_str); +#endif + get_uuid_string(uuid_str,sizeof(uuid_str)); + printf("uuid_str is %s\n",uuid_str); + return 0; +} + + +#endif |