1/* what follows is a somewhat stripped-down version of the sample 2 implementation of UUID generation from RFC 4122. */ 3 4/* 5** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. 6** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & 7** Digital Equipment Corporation, Maynard, Mass. 8** Copyright (c) 1998 Microsoft. 9** To anyone who acknowledges that this file is provided "AS IS" 10** without any express or implied warranty: permission to use, copy, 11** modify, and distribute this file for any purpose is hereby 12** granted without fee, provided that the above copyright notices and 13** this notice appears in all source code copies, and that none of 14** the names of Open Software Foundation, Inc., Hewlett-Packard 15** Company, Microsoft, or Digital Equipment Corporation be used in 16** advertising or publicity pertaining to distribution of the software 17** without specific, written prior permission. Neither Open Software 18** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital 19** Equipment Corporation makes any representations about the 20** suitability of this software for any purpose. 21*/ 22 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#include <fcntl.h> 31 32#if defined(HAVE_INTTYPES_H) 33#include <inttypes.h> 34#endif 35 36/* set the following to the number of 100ns ticks of the actual 37 resolution of your system's clock */ 38#define UUIDS_PER_TICK 1024 39 40#ifdef WIN32 41#include <windows.h> 42#include "missing\stdint.h" 43#define snprintf _snprintf 44#else 45 46#if HAVE_SYS_TYPES_H 47#include <sys/types.h> 48#else 49# if HAVE_STDINT_H 50# include <stdint.h> 51# endif 52#endif 53 54#if HAVE_SYS_TIME_H 55#include <sys/time.h> 56#endif 57 58#if HAVE_SYS_SYSINFO_H 59#include <sys/sysinfo.h> 60#endif 61 62#endif 63 64/* system dependent call to get the current system time. Returned as 65 100ns ticks since UUID epoch, but resolution may be less than 66 100ns. */ 67 68#ifdef WIN32 69#define I64(C) C 70#else 71#define I64(C) C##LL 72#endif 73 74typedef uint64_t uuid_time_t; 75 76typedef struct { 77 char nodeID[6]; 78} uuid_node_t; 79 80#undef uuid_t 81typedef struct { 82 uint32_t time_low; 83 uint16_t time_mid; 84 uint16_t time_hi_and_version; 85 uint8_t clock_seq_hi_and_reserved; 86 uint8_t clock_seq_low; 87 uint8_t node[6]; 88} uuid_t; 89 90/* some forward declarations. kind of wimpy to do that but heck, we 91 are all friends here right? raj 20081024 */ 92static uint16_t true_random(void); 93 94 95 96#ifdef WIN32 97 98static void get_system_time(uuid_time_t *uuid_time) 99{ 100 ULARGE_INTEGER time; 101 102 /* NT keeps time in FILETIME format which is 100ns ticks since 103 Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582. 104 The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec) 105 + 18 years and 5 leap days. */ 106 GetSystemTimeAsFileTime((FILETIME *)&time); 107 time.QuadPart += 108 109 (unsigned __int64) (1000*1000*10) // seconds 110 * (unsigned __int64) (60 * 60 * 24) // days 111 * (unsigned __int64) (17+30+31+365*18+5); // # of days 112 *uuid_time = time.QuadPart; 113} 114 115/* Sample code, not for use in production; see RFC 1750 */ 116static void get_random_info(char seed[16]) 117{ 118 uint16_t myrand; 119 int i; 120 121 i = 0; 122 do { 123 myrand = true_random(); 124 seed[i++] = myrand & 0xff; 125 seed[i++] = myrand >> 8; 126 } while (i < 14); 127 128} 129 130#else 131 132static void get_system_time(uuid_time_t *uuid_time) 133{ 134 struct timeval tp; 135 136 gettimeofday(&tp, (struct timezone *)0); 137 138 /* Offset between UUID formatted times and Unix formatted times. 139 UUID UTC base time is October 15, 1582. 140 Unix base time is January 1, 1970.*/ 141 *uuid_time = ((uint64_t)tp.tv_sec * 10000000) 142 + ((uint64_t)tp.tv_usec * 10) 143 + I64(0x01B21DD213814000); 144} 145 146/* Sample code, not for use in production; see RFC 1750 */ 147static void get_random_info(char seed[16]) 148{ 149 int fd; 150 uint16_t myrand; 151 int i; 152 153 /* we aren't all that picky, and we would rather not block so we 154 will use urandom */ 155 fd = open("/dev/urandom", O_RDONLY); 156 157 if (fd != -1) { 158 read(fd, seed, 16); 159 close(fd); 160 return; 161 } 162 163 /* ok, now what? */ 164 165 i = 0; 166 do { 167 myrand = true_random(); 168 seed[i++] = myrand & 0xff; 169 seed[i++] = myrand >> 8; 170 } while (i < 14); 171 172} 173 174#endif 175 176 177/* true_random -- generate a crypto-quality random number. 178**This sample doesn't do that.** */ 179static uint16_t true_random(void) 180{ 181 static int inited = 0; 182 uuid_time_t time_now; 183 184 if (!inited) { 185 get_system_time(&time_now); 186 time_now = time_now / UUIDS_PER_TICK; 187 srand((unsigned int) 188 (((time_now >> 32) ^ time_now) & 0xffffffff)); 189 inited = 1; 190 } 191 192 return (uint16_t)rand(); 193} 194 195/* puid -- print a UUID */ 196void puid(uuid_t u) 197{ 198 int i; 199 200 printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid, 201 u.time_hi_and_version, u.clock_seq_hi_and_reserved, 202 u.clock_seq_low); 203 for (i = 0; i < 6; i++) 204 printf("%2.2x", u.node[i]); 205 printf("\n"); 206} 207 208/* snpuid -- print a UUID in the supplied buffer */ 209void snpuid(char *str, size_t size, uuid_t u) { 210 int i; 211 char *tmp = str; 212 213 if (size < 38) { 214 snprintf(tmp,size,"%s","uuid string too small"); 215 return; 216 } 217 218 /* perhaps this is a trifle optimistic but what the heck */ 219 sprintf(tmp, 220 "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", 221 u.time_low, 222 u.time_mid, 223 u.time_hi_and_version, 224 u.clock_seq_hi_and_reserved, 225 u.clock_seq_low); 226 tmp += 24; 227 for (i = 0; i < 6; i++) { 228 sprintf(tmp,"%2.2x", u.node[i]); 229 tmp += 2; 230 } 231 *tmp = 0; 232 233} 234 235/* get-current_time -- get time as 60-bit 100ns ticks since UUID epoch. 236 Compensate for the fact that real clock resolution is 237 less than 100ns. */ 238static void get_current_time(uuid_time_t *timestamp) 239{ 240 static int inited = 0; 241 static uuid_time_t time_last; 242 static uint16_t uuids_this_tick; 243 uuid_time_t time_now; 244 245 if (!inited) { 246 get_system_time(&time_now); 247 uuids_this_tick = UUIDS_PER_TICK; 248 inited = 1; 249 } 250 251 for ( ; ; ) { 252 get_system_time(&time_now); 253 254 /* if clock reading changed since last UUID generated, */ 255 if (time_last != time_now) { 256 /* reset count of uuids gen'd with this clock reading */ 257 uuids_this_tick = 0; 258 time_last = time_now; 259 break; 260 } 261 if (uuids_this_tick < UUIDS_PER_TICK) { 262 uuids_this_tick++; 263 break; 264 } 265 /* going too fast for our clock; spin */ 266 } 267 /* add the count of uuids to low order bits of the clock reading */ 268 *timestamp = time_now + uuids_this_tick; 269} 270 271 272/* system dependent call to get IEEE node ID. 273 This sample implementation generates a random node ID. */ 274/* netperf mod - don't bother trying to read or write the nodeid */ 275static void get_ieee_node_identifier(uuid_node_t *node) 276{ 277 static int inited = 0; 278 static uuid_node_t saved_node; 279 char seed[16]; 280 281 if (!inited) { 282 get_random_info(seed); 283 seed[0] |= 0x01; 284 memcpy(&saved_node, seed, sizeof saved_node); 285 } 286 inited = 1; 287 288 *node = saved_node; 289} 290 291 292/* format_uuid_v1 -- make a UUID from the timestamp, clockseq, 293 and node ID */ 294static void format_uuid_v1(uuid_t* uuid, uint16_t clock_seq, 295 uuid_time_t timestamp, uuid_node_t node) 296{ 297 /* Construct a version 1 uuid with the information we've gathered 298 plus a few constants. */ 299 uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); 300 uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); 301 uuid->time_hi_and_version = 302 (unsigned short)((timestamp >> 48) & 0x0FFF); 303 uuid->time_hi_and_version |= (1 << 12); 304 uuid->clock_seq_low = clock_seq & 0xFF; 305 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8; 306 uuid->clock_seq_hi_and_reserved |= 0x80; 307 memcpy(&uuid->node, &node, sizeof uuid->node); 308} 309 310/* uuid_create -- generator a UUID */ 311int uuid_create(uuid_t *uuid) 312{ 313 uuid_time_t timestamp; 314 uint16_t clockseq; 315 uuid_node_t node; 316 317 /* get time, node ID, saved state from non-volatile storage */ 318 get_current_time(×tamp); 319 get_ieee_node_identifier(&node); 320 321 /* for us clockseq is always to be random as we have no state */ 322 clockseq = true_random(); 323 324 /* stuff fields into the UUID */ 325 format_uuid_v1(uuid, clockseq, timestamp, node); 326 return 1; 327} 328 329void get_uuid_string(char *uuid_str, size_t size) { 330 uuid_t u; 331 332 uuid_create(&u); 333 snpuid(uuid_str,size,u); 334 335 return; 336} 337 338#ifdef NETPERF_STANDALONE_DEBUG 339 340int 341main(int argc, char *argv[]) 342{ 343 uuid_t u; 344 char uuid_str[38]; 345#if 0 346 uuid_create(&u); 347 printf("uuid_create(): "); puid(u); 348 snpuid(uuid_str,sizeof(uuid_str),u); 349 printf("\nas a string %s\n",uuid_str); 350#endif 351 get_uuid_string(uuid_str,sizeof(uuid_str)); 352 printf("uuid_str is %s\n",uuid_str); 353 return 0; 354} 355 356 357#endif 358