• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
74 typedef uint64_t uuid_time_t;
75 
76 typedef struct {
77   char nodeID[6];
78 } uuid_node_t;
79 
80 #undef uuid_t
81 typedef 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 */
92 static uint16_t true_random(void);
93 
94 
95 
96 #ifdef WIN32
97 
get_system_time(uuid_time_t * uuid_time)98 static 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 */
get_random_info(char seed[16])116 static 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 
get_system_time(uuid_time_t * uuid_time)132 static 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 */
get_random_info(char seed[16])147 static 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.** */
true_random(void)179 static 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 */
puid(uuid_t u)196 void 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 */
snpuid(char * str,size_t size,uuid_t u)209 void 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. */
get_current_time(uuid_time_t * timestamp)238 static 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 */
get_ieee_node_identifier(uuid_node_t * node)275 static 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 */
format_uuid_v1(uuid_t * uuid,uint16_t clock_seq,uuid_time_t timestamp,uuid_node_t node)294 static 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 */
uuid_create(uuid_t * uuid)311 int 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(&timestamp);
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 
get_uuid_string(char * uuid_str,size_t size)329 void 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 
340 int
main(int argc,char * argv[])341 main(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