2 * gen_uuid.c --- generate a DCE-compatible uuid
4 * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, and the entire permission notice in its entirety,
12 * including the disclaimer of warranties.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
23 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
41 #include <sys/types.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
49 #include <sys/sockio.h>
51 #include <netinet/in.h>
52 #include <net/if_dl.h>
53 #include <sys/resource.h>
58 #define srand(x) srandom(x)
59 #define rand() random()
63 #define THREAD_LOCAL static TLS
65 #define THREAD_LOCAL static
68 #if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
70 THREAD_LOCAL
unsigned short jrand_seed
[3];
73 static int get_random_fd(void)
81 fd
= open("/dev/urandom", O_RDONLY
);
83 fd
= open("/dev/random", O_RDONLY
| O_NONBLOCK
);
85 i
= fcntl(fd
, F_GETFD
);
87 fcntl(fd
, F_SETFD
, i
| FD_CLOEXEC
);
89 srand((getpid() << 16) ^ getuid() ^ tv
.tv_sec
^ tv
.tv_usec
);
91 jrand_seed
[0] = getpid() ^ (tv
.tv_sec
& 0xFFFF);
92 jrand_seed
[1] = getppid() ^ (tv
.tv_usec
& 0xFFFF);
93 jrand_seed
[2] = (tv
.tv_sec
^ tv
.tv_usec
) >> 16;
96 /* Crank the random number generator a few times */
98 for (i
= (tv
.tv_sec
^ tv
.tv_usec
) & 0x1F; i
> 0; i
--)
105 * Generate a series of random bytes. Use /dev/urandom if possible,
106 * and if not, use srandom/random.
108 static void get_random_bytes(void *buf
, int nbytes
)
110 int i
, n
= nbytes
, fd
= get_random_fd();
111 int lose_counter
= 0;
112 unsigned char *cp
= buf
;
118 if (lose_counter
++ > 16)
129 * We do this all the time, but this is the only source of
130 * randomness if /dev/random/urandom is out to lunch.
132 for (cp
= buf
, i
= 0; i
< nbytes
; i
++)
133 *cp
++ ^= (rand() >> 7) & 0xFF;
136 unsigned short tmp_seed
[3];
138 memcpy(tmp_seed
, jrand_seed
, sizeof(tmp_seed
));
139 jrand_seed
[2] = jrand_seed
[2] ^ syscall(__NR_gettid
);
140 for (cp
= buf
, i
= 0; i
< nbytes
; i
++)
141 *cp
++ ^= (jrand48(tmp_seed
) >> 7) & 0xFF;
142 memcpy(jrand_seed
, tmp_seed
,
143 sizeof(jrand_seed
) - sizeof(unsigned short));
152 * Get the ethernet hardware address, if we can find it...
154 * XXX for a windows version, probably should use GetAdaptersInfo:
155 * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
156 * commenting out get_node_id just to get gen_uuid to compile under windows
157 * is not the right way to go!
159 static int get_node_id(unsigned char *node_id
)
162 struct ifreq ifr
, *ifrp
;
167 struct sockaddr_dl
*sdlp
;
170 * BSD 4.4 defines the size of an ifreq to be
171 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
172 * However, under earlier systems, sa_len isn't present, so the size is
173 * just sizeof(struct ifreq)
176 #define max(a,b) ((a) > (b) ? (a) : (b))
178 #define ifreq_size(i) max(sizeof(struct ifreq),\
179 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
181 sd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
185 memset(buf
, 0, sizeof(buf
));
186 ifc
.ifc_len
= sizeof(buf
);
188 if (ioctl (sd
, SIOCGIFCONF
, (char *)&ifc
) < 0) {
193 for (i
= 0; i
< n
; i
+= ifreq_size(*ifrp
) ) {
194 ifrp
= (struct ifreq
*)((char *) ifc
.ifc_buf
+i
);
195 strncpy(ifr
.ifr_name
, ifrp
->ifr_name
, IFNAMSIZ
);
197 if (ioctl(sd
, SIOCGIFHWADDR
, &ifr
) < 0)
199 a
= (unsigned char *) &ifr
.ifr_hwaddr
.sa_data
;
202 if (ioctl(sd
, SIOCGENADDR
, &ifr
) < 0)
204 a
= (unsigned char *) ifr
.ifr_enaddr
;
206 sdlp
= (struct sockaddr_dl
*) &ifrp
->ifr_addr
;
207 if ((sdlp
->sdl_family
!= AF_LINK
) || (sdlp
->sdl_alen
!= 6))
209 a
= (unsigned char *) &sdlp
->sdl_data
[sdlp
->sdl_nlen
];
210 #endif /* SIOCGENADDR */
211 #endif /* SIOCGIFHWADDR */
212 if (!a
[0] && !a
[1] && !a
[2] && !a
[3] && !a
[4] && !a
[5])
215 memcpy(node_id
, a
, 6);
224 /* Assume that the gettimeofday() has microsecond granularity */
225 #define MAX_ADJUSTMENT 10
227 static int get_clock(uint32_t *clock_high
, uint32_t *clock_low
,
228 uint16_t *ret_clock_seq
, int *num
)
230 THREAD_LOCAL
int adjustment
= 0;
231 THREAD_LOCAL
struct timeval last
= {0, 0};
232 THREAD_LOCAL
int state_fd
= -2;
233 THREAD_LOCAL
FILE *state_f
;
234 THREAD_LOCAL
uint16_t clock_seq
;
241 if (state_fd
== -2) {
242 save_umask
= umask(0);
243 state_fd
= open("/var/lib/libuuid/clock.txt",
244 O_RDWR
|O_CREAT
, 0660);
245 (void) umask(save_umask
);
247 state_f
= fdopen(state_fd
, "r+");
255 fl
.l_whence
= SEEK_SET
;
261 while (fcntl(state_fd
, F_SETLKW
, &fl
) < 0) {
262 if ((errno
== EAGAIN
) || (errno
== EINTR
))
271 unsigned long tv1
, tv2
;
274 if (fscanf(state_f
, "clock: %04x tv: %lu %lu adj: %d\n",
275 &cl
, &tv1
, &tv2
, &a
) == 4) {
276 clock_seq
= cl
& 0x3FFF;
283 if ((last
.tv_sec
== 0) && (last
.tv_usec
== 0)) {
284 get_random_bytes(&clock_seq
, sizeof(clock_seq
));
286 gettimeofday(&last
, 0);
291 gettimeofday(&tv
, 0);
292 if ((tv
.tv_sec
< last
.tv_sec
) ||
293 ((tv
.tv_sec
== last
.tv_sec
) &&
294 (tv
.tv_usec
< last
.tv_usec
))) {
295 clock_seq
= (clock_seq
+1) & 0x3FFF;
298 } else if ((tv
.tv_sec
== last
.tv_sec
) &&
299 (tv
.tv_usec
== last
.tv_usec
)) {
300 if (adjustment
>= MAX_ADJUSTMENT
)
308 clock_reg
= tv
.tv_usec
*10 + adjustment
;
309 clock_reg
+= ((uint64_t) tv
.tv_sec
)*10000000;
310 clock_reg
+= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
312 if (num
&& (*num
> 1)) {
313 adjustment
+= *num
- 1;
314 last
.tv_usec
+= adjustment
/ 10;
315 adjustment
= adjustment
% 10;
316 last
.tv_sec
+= last
.tv_usec
/ 1000000;
317 last
.tv_usec
= last
.tv_usec
% 1000000;
322 len
= fprintf(state_f
,
323 "clock: %04x tv: %016lu %08lu adj: %08d\n",
324 clock_seq
, last
.tv_sec
, (long)last
.tv_usec
,
327 if (ftruncate(state_fd
, len
) < 0) {
328 fprintf(state_f
, " \n");
333 if (fcntl(state_fd
, F_SETLK
, &fl
) < 0) {
339 *clock_high
= clock_reg
>> 32;
340 *clock_low
= clock_reg
;
341 *ret_clock_seq
= clock_seq
;
345 void uuid__generate_time(uuid_t out
, int *num
)
347 static unsigned char node_id
[6];
348 static int has_init
= 0;
353 if (get_node_id(node_id
) <= 0) {
354 get_random_bytes(node_id
, 6);
356 * Set multicast bit, to prevent conflicts
357 * with IEEE 802 addresses obtained from
364 get_clock(&clock_mid
, &uu
.time_low
, &uu
.clock_seq
, num
);
365 uu
.clock_seq
|= 0x8000;
366 uu
.time_mid
= (uint16_t) clock_mid
;
367 uu
.time_hi_and_version
= ((clock_mid
>> 16) & 0x0FFF) | 0x1000;
368 memcpy(uu
.node
, node_id
, 6);
372 void uuid_generate_time(uuid_t out
)
375 THREAD_LOCAL
int num
= 0;
376 THREAD_LOCAL
struct uuid uu
;
377 THREAD_LOCAL
time_t last_time
= 0;
382 if (now
> last_time
+1)
389 uuid_unpack(out
, &uu
);
397 if (uu
.time_low
== 0) {
399 if (uu
.time_mid
== 0)
400 uu
.time_hi_and_version
++;
411 uuid__generate_time(out
, 0);
413 #endif // !_KERNEL_MODE
415 void uuid__generate_random(uuid_t out
, int *num
)
426 for (i
= 0; i
< n
; i
++) {
427 get_random_bytes(buf
, sizeof(buf
));
428 uuid_unpack(buf
, &uu
);
430 uu
.clock_seq
= (uu
.clock_seq
& 0x3FFF) | 0x8000;
431 uu
.time_hi_and_version
= (uu
.time_hi_and_version
& 0x0FFF)
434 out
+= sizeof(uuid_t
);
438 void uuid_generate_random(uuid_t out
)
441 /* No real reason to use the daemon for random uuid's -- yet */
443 uuid__generate_random(out
, &num
);
447 * Check whether good random source (/dev/random or /dev/urandom)
450 static int have_random_source(void)
454 return (!stat("/dev/random", &s
) || !stat("/dev/urandom", &s
));
460 * This is the generic front-end to uuid_generate_random and
461 * uuid_generate_time. It uses uuid_generate_random only if
462 * /dev/urandom is available, since otherwise we won't have
463 * high-quality randomness.
465 void uuid_generate(uuid_t out
)
467 if (have_random_source())
468 uuid_generate_random(out
);
470 uuid_generate_time(out
);
473 void uuid_generate(uuid_t out
)
475 uuid_generate_random(out
);