EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FairRunIdGenerator.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FairRunIdGenerator.cxx
1 /*
2  * gen_uuid.c --- generate a DCE-compatible uuid
3  *
4  * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU
8  * Library General Public License.
9  * %End-Header%
10  */
11 
12 /*
13  * Force inclusion of SVID stuff since we need it if we're compiling in
14  * gcc-wall wall mode
15  */
16 #define _SVID_SOURCE
17 
18 #include "unistd.h"
19 #include "stdlib.h"
20 #include "string.h"
21 #include "fcntl.h"
22 #include "errno.h"
23 #include "sys/types.h"
24 #include "sys/time.h"
25 #include "sys/stat.h"
26 #include "sys/file.h"
27 #include "sys/ioctl.h"
28 #include "sys/socket.h"
29 #include "net/if.h"
30 #include "netinet/in.h"
31 
32 #define srand(x) srandom(x)
33 #define rand() random()
34 
35 //#include "genid32.h" replaced by hrunidgenerator.h
36 
37 /*
38  * uuid.h -- private header file for uuids
39  *
40  * Copyright (C) 1996, 1997 Theodore Ts'o.
41  *
42  * %Begin-Header%
43  * This file may be redistributed under the terms of the GNU
44  * Library General Public License.
45  * %End-Header%
46  */
47 
48 #include "FairRunIdGenerator.h"
49 
50 /*
51  * Offset between 15-Oct-1582 and 1-Jan-70
52  */
53 #define TIME_OFFSET_HIGH 0x01B21DD2
54 #define TIME_OFFSET_LOW 0x13814000
55 
57 {
58  struct timeval tv;
59  static int fd = -2;
60  int i;
61 
62  if (fd == -2) {
63  gettimeofday(&tv, 0);
64  fd = open("/dev/urandom", O_RDONLY);
65  if (fd == -1) {
66  fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
67  }
68  srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
69  }
70  /* Crank the random number generator a few times */
71  gettimeofday(&tv, 0);
72  for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) {
73  rand();
74  }
75  return fd;
76 }
77 
78 
79 /*
80  * Generate a series of random bytes. Use /dev/urandom if possible,
81  * and if not, use srandom/random.
82  */
83 void FairRunIdGenerator::get_random_bytes(void* buf, int nbytes)
84 {
85  int i, fd = get_random_fd();
86  int lose_counter = 0;
87  char* cp = (char*) buf;
88 
89  if (fd >= 0) {
90  while (nbytes > 0) {
91  i = read(fd, cp, nbytes);
92  if ((i < 0) &&
93  ((errno == EINTR) || (errno == EAGAIN))) {
94  continue;
95  }
96  if (i <= 0) {
97  if (lose_counter++ == 8) {
98  break;
99  }
100  continue;
101  }
102  nbytes -= i;
103  cp += i;
104  lose_counter = 0;
105  }
106  }
107  /* XXX put something better here if no /dev/random! */
108  for (i = 0; i < nbytes; i++) {
109  *cp++ = rand() & 0xFF;
110  }
111  return;
112 }
113 
114 /*
115  * Get the ethernet hardware address, if we can find it...
116  */
117 int FairRunIdGenerator::get_node_id(unsigned char* node_id)
118 {
119 #ifdef HAVE_NET_IF_H
120  int sd;
121  struct ifreq ifr, *ifrp;
122  struct ifconf ifc;
123  char buf[1024];
124  int n, i;
125  unsigned char* a;
126 
127  /*
128  * BSD 4.4 defines the size of an ifreq to be
129  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
130  * However, under earlier systems, sa_len isn't present, so the size is
131  * just sizeof(struct ifreq)
132  */
133 #ifdef HAVE_SA_LEN
134 #ifndef max
135 #define max(a,b) ((a) > (b) ? (a) : (b))
136 #endif
137 #define ifreq_size(i) max(sizeof(struct ifreq),\
138  sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
139 #else
140 #define ifreq_size(i) sizeof(struct ifreq)
141 #endif /* HAVE_SA_LEN*/
142 
143  sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
144  if (sd < 0) {
145  return -1;
146  }
147  memset(buf, 0, sizeof(buf));
148  ifc.ifc_len = sizeof(buf);
149  ifc.ifc_buf = buf;
150  if (ioctl(sd, SIOCGIFCONF, (char*) &ifc) < 0) {
151  close(sd);
152  return -1;
153  }
154  n = ifc.ifc_len;
155  for (i = 0; i < n; i += ifreq_size(*ifr)) {
156  ifrp = (struct ifreq*) ((char*) ifc.ifc_buf + i);
157  strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
158 #ifdef SIOCGIFHWADDR
159  if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) {
160  continue;
161  }
162  a = (unsigned char*) &ifr.ifr_hwaddr.sa_data;
163 #else
164 #ifdef SIOCGENADDR
165  if (ioctl(sd, SIOCGENADDR, &ifr) < 0) {
166  continue;
167  }
168  a = (unsigned char*) ifr.ifr_enaddr;
169 #else
170  /*
171  * XXX we don't have a way of getting the hardware
172  * address
173  */
174  close(sd);
175  return 0;
176 #endif /* SIOCGENADDR */
177 #endif /* SIOCGIFHWADDR */
178  if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) {
179  continue;
180  }
181  if (node_id) {
182  memcpy(node_id, a, 6);
183  close(sd);
184  return 1;
185  }
186  }
187  close(sd);
188 #endif
189  return 0;
190 }
191 
192 /* Assume that the gettimeofday() has microsecond granularity */
193 #define MAX_ADJUSTMENT 10
194 
195 int FairRunIdGenerator::get_clock(uint32_t* clock_high, uint32_t* clock_low, uint16_t* ret_clock_seq)
196 {
197  static int adjustment = 0;
198  static struct timeval last =
199  {0, 0};
200  static uint16_t clock_seq;
201  struct timeval tv;
202  unsigned long long clock_reg;
203 
204 try_again:
205  gettimeofday(&tv, 0);
206  if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
207  get_random_bytes(&clock_seq, sizeof(clock_seq));
208  clock_seq &= 0x1FFF;
209  last = tv;
210  last.tv_sec--;
211  }
212  if ((tv.tv_sec < last.tv_sec) ||
213  ((tv.tv_sec == last.tv_sec) &&
214  (tv.tv_usec < last.tv_usec))) {
215  clock_seq = (clock_seq + 1) & 0x1FFF;
216  adjustment = 0;
217  last = tv;
218  } else if ((tv.tv_sec == last.tv_sec) &&
219  (tv.tv_usec == last.tv_usec)) {
220  if (adjustment >= MAX_ADJUSTMENT) {
221  goto try_again;
222  }
223  adjustment++;
224  } else {
225  adjustment = 0;
226  last = tv;
227  }
228 
229  clock_reg = tv.tv_usec * 10 + adjustment;
230  clock_reg += ((unsigned long long) tv.tv_sec) * 10000000;
231  clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
232 
233  *clock_high = clock_reg >> 32;
234  *clock_low = clock_reg;
235  *ret_clock_seq = clock_seq;
236  return 0;
237 }
238 
240 {
241  static unsigned char node_id[6];
242  static int has_init = 0;
243  struct uuid uu;
244  uint32_t clock_mid;
245 
246  if (!has_init) {
247  if (get_node_id(node_id) <= 0) {
248  get_random_bytes(node_id, 6);
249  /*
250  * Set multicast bit, to prevent conflicts
251  * with IEEE 802 addresses obtained from
252  * network cards
253  */
254  node_id[0] |= 0x80;
255  }
256  has_init = 1;
257  }
258  get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
259  uu.clock_seq |= 0x8000;
260  uu.time_mid = (uint16_t) clock_mid;
261  uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
262  memcpy(uu.node, node_id, 6);
263  uuid_pack(&uu, out);
264 }
265 
267 {
268  uuid_t buf;
269  struct uuid uu;
270 
271  get_random_bytes(buf, sizeof(buf));
272  uuid_unpack(buf, &uu);
273 
274  uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
275  uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
276  uuid_pack(&uu, out);
277 }
278 
279 /*
280  * This is the generic front-end to uuid_generate_random and
281  * uuid_generate_time. It uses uuid_generate_random only if
282  * /dev/urandom is available, since otherwise we won't have
283  * high-quality randomness.
284  */
286 {
287  if (get_random_fd() >= 0) {
289  } else {
290  uuid_generate_time(out);
291  }
292 }
293 
294 /*
295  * Internal routine for packing UUID's
296  *
297  * Copyright (C) 1996, 1997 Theodore Ts'o.
298  *
299  * %Begin-Header%
300  * This file may be redistributed under the terms of the GNU
301  * Library General Public License.
302  * %End-Header%
303  */
304 
305 void FairRunIdGenerator::uuid_pack(const struct uuid* uu, uuid_t ptr)
306 {
307  uint32_t tmp;
308  unsigned char* out = ptr;
309 
310  tmp = uu->time_low;
311  out[3] = (unsigned char) tmp;
312  tmp >>= 8;
313  out[2] = (unsigned char) tmp;
314  tmp >>= 8;
315  out[1] = (unsigned char) tmp;
316  tmp >>= 8;
317  out[0] = (unsigned char) tmp;
318 
319  tmp = uu->time_mid;
320  out[5] = (unsigned char) tmp;
321  tmp >>= 8;
322  out[4] = (unsigned char) tmp;
323 
324  tmp = uu->time_hi_and_version;
325  out[7] = (unsigned char) tmp;
326  tmp >>= 8;
327  out[6] = (unsigned char) tmp;
328 
329  tmp = uu->clock_seq;
330  out[9] = (unsigned char) tmp;
331  tmp >>= 8;
332  out[8] = (unsigned char) tmp;
333 
334  memcpy(out + 10, uu->node, 6);
335 }
336 
337 
338 /*
339  * Internal routine for unpacking UUID
340  *
341  * Copyright (C) 1996, 1997 Theodore Ts'o.
342  *
343  * %Begin-Header%
344  * This file may be redistributed under the terms of the GNU
345  * Library General Public License.
346  * %End-Header%
347  */
348 
350 {
351  const uint8_t* ptr = in;
352  uint32_t tmp;
353 
354  tmp = *ptr++;
355  tmp = (tmp << 8) | *ptr++;
356  tmp = (tmp << 8) | *ptr++;
357  tmp = (tmp << 8) | *ptr++;
358  uu->time_low = tmp;
359 
360  tmp = *ptr++;
361  tmp = (tmp << 8) | *ptr++;
362  uu->time_mid = tmp;
363 
364  tmp = *ptr++;
365  tmp = (tmp << 8) | *ptr++;
366  uu->time_hi_and_version = tmp;
367 
368  tmp = *ptr++;
369  tmp = (tmp << 8) | *ptr++;
370  uu->clock_seq = tmp;
371 
372  memcpy(uu->node, ptr, 6);
373 }
374 
376 {
377  uuid_t uu;
378  unsigned int v;
379 
380  uuid_generate(uu);
381  v = ((uu[0] ^ uu[4] ^ uu[8] ^ uu[12]) << 0)
382  | ((uu[1] ^ uu[5] ^ uu[9] ^ uu[13]) << 8)
383  | ((uu[2] ^ uu[6] ^ uu[10] ^ uu[14]) << 16)
384  | ((uu[3] ^ uu[7] ^ uu[11] ^ uu[15]) << 24);
385  return v & 0x7fffffff;
386 }