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(&timestamp);
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