FairRoot
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FairRunIdGenerator.cxx
Go to the documentation of this file.
1 /********************************************************************************
2  * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
3  * *
4  * This software is distributed under the terms of the *
5  * GNU Lesser General Public Licence (LGPL) version 3, *
6  * copied verbatim in the file "LICENSE" *
7  ********************************************************************************/
8 /*
9  * gen_uuid.c --- generate a DCE-compatible uuid
10  *
11  * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
12  *
13  * %Begin-Header%
14  * This file may be redistributed under the terms of the GNU
15  * Library General Public License.
16  * %End-Header%
17  */
18 
19 /*
20  * Force inclusion of SVID stuff since we need it if we're compiling in
21  * gcc-wall wall mode
22  */
23 #define _SVID_SOURCE
24 #define _DEFAULT_SOURCE
25 
26 #include "FairRunIdGenerator.h"
27 
28 #include <stdlib.h> // for rand, srand
29 #include <string.h> // for memcpy
30 #include <sys/errno.h> // for errno, EAGAIN, EINTR
31 #include <sys/fcntl.h> // for open, O_RDONLY, O_NONBLOCK
32 #include <sys/time.h> // for gettimeofday
33 #include <unistd.h> // for getpid, getuid, read
34 
35 #define srand(x) srandom(x)
36 #define rand() random()
37 
38 // using namespace std;
39 
40 //#include "genid32.h" replaced by hrunidgenerator.h
41 
42 /*
43  * uuid.h -- private header file for uuids
44  *
45  * Copyright (C) 1996, 1997 Theodore Ts'o.
46  *
47  * %Begin-Header%
48  * This file may be redistributed under the terms of the GNU
49  * Library General Public License.
50  * %End-Header%
51  */
52 
53 /*
54  * Offset between 15-Oct-1582 and 1-Jan-70
55  */
56 #define TIME_OFFSET_HIGH 0x01B21DD2
57 #define TIME_OFFSET_LOW 0x13814000
58 
59 int FairRunIdGenerator::get_random_fd(void)
60 {
61  struct timeval tv;
62  static int fd = -2;
63  int i;
64 
65  if (fd == -2) {
66  gettimeofday(&tv, 0);
67  fd = open("/dev/urandom", O_RDONLY);
68  if (fd == -1) {
69  fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
70  }
71  srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
72  }
73  /* Crank the random number generator a few times */
74  gettimeofday(&tv, 0);
75  for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) {
76  rand();
77  }
78  return fd;
79 }
80 
81 /*
82  * Generate a series of random bytes. Use /dev/urandom if possible,
83  * and if not, use srandom/random.
84  */
85 void FairRunIdGenerator::get_random_bytes(void* buf, int nbytes)
86 {
87  int i, fd = get_random_fd();
88  int lose_counter = 0;
89  char* cp = static_cast<char*>(buf);
90 
91  if (fd >= 0) {
92  while (nbytes > 0) {
93  i = read(fd, cp, nbytes);
94  if ((i < 0) && ((errno == EINTR) || (errno == EAGAIN))) {
95  continue;
96  }
97  if (i <= 0) {
98  if (lose_counter++ == 8) {
99  break;
100  }
101  continue;
102  }
103  nbytes -= i;
104  cp += i;
105  lose_counter = 0;
106  }
107  }
108  /* XXX put something better here if no /dev/random! */
109  for (i = 0; i < nbytes; i++) {
110  *cp++ = rand() & 0xFF;
111  }
112  return;
113 }
114 
115 /*
116  * Get the ethernet hardware address, if we can find it...
117  */
118 int FairRunIdGenerator::get_node_id(unsigned char* /*node_id*/)
119 {
120 #ifdef HAVE_NET_IF_H
121  int sd;
122  struct ifreq ifr, *ifrp;
123  struct ifconf ifc;
124  char buf[1024];
125  int n, i;
126  unsigned char* a;
127 
128  /*
129  * BSD 4.4 defines the size of an ifreq to be
130  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
131  * However, under earlier systems, sa_len isn't present, so the size is
132  * just sizeof(struct ifreq)
133  */
134 #ifdef HAVE_SA_LEN
135 #ifndef max
136 #define max(a, b) ((a) > (b) ? (a) : (b))
137 #endif
138 #define ifreq_size(i) max(sizeof(struct ifreq), 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 = {0, 0};
199  static uint16_t clock_seq;
200  struct timeval tv;
201  unsigned long long clock_reg;
202 
203 try_again:
204  gettimeofday(&tv, 0);
205  if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
206  get_random_bytes(&clock_seq, sizeof(clock_seq));
207  clock_seq &= 0x1FFF;
208  last = tv;
209  last.tv_sec--;
210  }
211  if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) {
212  clock_seq = (clock_seq + 1) & 0x1FFF;
213  adjustment = 0;
214  last = tv;
215  } else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) {
216  if (adjustment >= MAX_ADJUSTMENT) {
217  goto try_again;
218  }
219  adjustment++;
220  } else {
221  adjustment = 0;
222  last = tv;
223  }
224 
225  clock_reg = tv.tv_usec * 10 + adjustment;
226  clock_reg += (static_cast<unsigned long long>(tv.tv_sec)) * 10000000;
227  clock_reg += ((static_cast<unsigned long long>(0x01B21DD2)) << 32) + 0x13814000;
228 
229  *clock_high = clock_reg >> 32;
230  *clock_low = clock_reg;
231  *ret_clock_seq = clock_seq;
232 
233  fTimeSpec.tv_sec = last.tv_sec;
234  // fTimeSpec.tv_nsec = last.tv_usec*1000.;
235  fTimeSpec.tv_nsec = 0.;
236 
237  return 0;
238 }
239 
240 void FairRunIdGenerator::uuid_generate_time(uuid_t out)
241 {
242  static unsigned char node_id[6];
243  static int has_init = 0;
244  struct uuid uu;
245  uint32_t clock_mid;
246 
247  if (!has_init) {
248  if (get_node_id(node_id) <= 0) {
249  get_random_bytes(node_id, 6);
250  /*
251  * Set multicast bit, to prevent conflicts
252  * with IEEE 802 addresses obtained from
253  * network cards
254  */
255  node_id[0] |= 0x80;
256  }
257  has_init = 1;
258  }
259  get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
260  uu.clock_seq |= 0x8000;
261  uu.time_mid = static_cast<uint16_t>(clock_mid);
262  uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
263  memcpy(uu.node, node_id, 6);
264  uuid_pack(&uu, out);
265 }
266 
267 void FairRunIdGenerator::uuid_generate_random(uuid_t out)
268 {
269  uuid_t buf;
270  struct uuid uu;
271 
272  get_random_bytes(buf, sizeof(buf));
273  uuid_unpack(buf, &uu);
274 
275  uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
276  uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
277  uuid_pack(&uu, out);
278 }
279 
280 /*
281  * This is the generic front-end to uuid_generate_random and
282  * uuid_generate_time. It uses uuid_generate_random only if
283  * /dev/urandom is available, since otherwise we won't have
284  * high-quality randomness.
285  */
286 void FairRunIdGenerator::uuid_generate(uuid_t out)
287 {
288  /*
289  if (get_random_fd() >= 0) {
290  uuid_generate_random(out);
291  } else {
292  uuid_generate_time(out);
293  }
294  */
295  uuid_generate_time(out);
296 }
297 
298 /*
299  * Internal routine for packing UUID's
300  *
301  * Copyright (C) 1996, 1997 Theodore Ts'o.
302  *
303  * %Begin-Header%
304  * This file may be redistributed under the terms of the GNU
305  * Library General Public License.
306  * %End-Header%
307  */
308 
309 void FairRunIdGenerator::uuid_pack(const struct uuid* uu, uuid_t ptr)
310 {
311  uint32_t tmp;
312  unsigned char* out = ptr;
313 
314  tmp = uu->time_low;
315  out[3] = static_cast<unsigned char>(tmp);
316  tmp >>= 8;
317  out[2] = static_cast<unsigned char>(tmp);
318  tmp >>= 8;
319  out[1] = static_cast<unsigned char>(tmp);
320  tmp >>= 8;
321  out[0] = static_cast<unsigned char>(tmp);
322 
323  tmp = uu->time_mid;
324  out[5] = static_cast<unsigned char>(tmp);
325  tmp >>= 8;
326  out[4] = static_cast<unsigned char>(tmp);
327 
328  tmp = uu->time_hi_and_version;
329  out[7] = static_cast<unsigned char>(tmp);
330  tmp >>= 8;
331  out[6] = static_cast<unsigned char>(tmp);
332 
333  tmp = uu->clock_seq;
334  out[9] = static_cast<unsigned char>(tmp);
335  tmp >>= 8;
336  out[8] = static_cast<unsigned char>(tmp);
337 
338  memcpy(out + 10, uu->node, 6);
339 }
340 
341 /*
342  * Internal routine for unpacking UUID
343  *
344  * Copyright (C) 1996, 1997 Theodore Ts'o.
345  *
346  * %Begin-Header%
347  * This file may be redistributed under the terms of the GNU
348  * Library General Public License.
349  * %End-Header%
350  */
351 
352 void FairRunIdGenerator::uuid_unpack(const uuid_t in, struct uuid* uu)
353 {
354  const uint8_t* ptr = in;
355  uint32_t tmp;
356 
357  tmp = *ptr++;
358  tmp = (tmp << 8) | *ptr++;
359  tmp = (tmp << 8) | *ptr++;
360  tmp = (tmp << 8) | *ptr++;
361  uu->time_low = tmp;
362 
363  tmp = *ptr++;
364  tmp = (tmp << 8) | *ptr++;
365  uu->time_mid = tmp;
366 
367  tmp = *ptr++;
368  tmp = (tmp << 8) | *ptr++;
369  uu->time_hi_and_version = tmp;
370 
371  tmp = *ptr++;
372  tmp = (tmp << 8) | *ptr++;
373  uu->clock_seq = tmp;
374 
375  memcpy(uu->node, ptr, 6);
376 }
377 
379 {
380  uuid_t uu;
381  // unsigned int v;
382  // struct timeval ret_tv;
383  uuid_generate(uu);
384 
385  /*
386  v = ((uu[0] ^ uu[4] ^ uu[8] ^ uu[12]) << 0)
387  | ((uu[1] ^ uu[5] ^ uu[9] ^ uu[13]) << 8)
388  | ((uu[2] ^ uu[6] ^ uu[10] ^ uu[14]) << 16)
389  | ((uu[3] ^ uu[7] ^ uu[11] ^ uu[15]) << 24);
390 */
391 
392  // return v & 0x7fffffff;
393  return getTID();
394 }
395 
396 unsigned int FairRunIdGenerator::getTID() { return (fTimeSpec.tv_sec); }
397 
398 struct timespec FairRunIdGenerator::getTimeSpecFromTID(unsigned int ms)
399 {
400  struct timespec ret_tv;
401  ret_tv.tv_sec = ms;
402  ret_tv.tv_nsec = 0.; // truncate the ns resolution
403  return ret_tv;
404 }
unsigned char uuid_t[16]
unsigned int generateId(void)
unsigned char uint8_t
parOut open("mq_ex_params.root")
unsigned short int uint16_t
#define srand(x)
#define rand()
#define MAX_ADJUSTMENT
unsigned int uint32_t