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
74typedef uint64_t uuid_time_t;
75
76typedef struct {
77  char nodeID[6];
78} uuid_node_t;
79
80#undef uuid_t
81typedef 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 */
92static uint16_t true_random(void);
93
94
95
96#ifdef WIN32
97
98static 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 */
116static 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
132static 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 */
147static 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.** */
179static 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 */
196void 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 */
209void 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. */
238static 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 */
275static 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 */
294static 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 */
311int 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
329void 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
340int
341main(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