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