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(×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
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