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