solaris-uniqtime32-20051223
[openafs.git] / src / util / uuid.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* String conversion routines have the following copyright */
11
12 /*
13  * Copyright (c) 2002 Kungliga Tekniska Högskolan
14  * (Royal Institute of Technology, Stockholm, Sweden).
15  * All rights reserved.
16  * 
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  * 
28  * 3. Neither the name of the Institute nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  * 
32  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  */
44
45 #include <afsconfig.h>
46 #ifdef KERNEL
47 #include "afs/param.h"
48 #else
49 #include <afs/param.h>
50 #endif
51
52 RCSID
53     ("$Header$");
54
55 #ifdef KERNEL
56 #include "afs/sysincludes.h"
57 #include "afsincludes.h"
58 #define uuid_memcmp(A,B,C)      memcmp(A, B, C)
59 #define uuid_memcpy(A,B,C)      memcpy(A, B, C)
60 #else /* KERNEL */
61 #include <stdio.h>
62 #include <errno.h>
63 #ifdef AFS_NT40_ENV
64 #include <winsock2.h>
65 #include <process.h>
66 #else
67 #include <sys/file.h>
68 #include <netinet/in.h>
69 #include <netdb.h>
70 #include <sys/ioctl.h>
71 #include <sys/socket.h>
72 #ifndef ITIMER_REAL
73 #include <sys/time.h>
74 #endif /* ITIMER_REAL */
75 #include <net/if.h>
76 #ifdef HAVE_STRING_H
77 #include <string.h>
78 #else
79 #ifdef HAVE_STRINGS_H
80 #include <strings.h>
81 #endif
82 #endif
83 #ifdef HAVE_UNISTD_H
84 #include <unistd.h>
85 #endif
86 #include <stdlib.h>
87 #endif
88 #include <sys/stat.h>
89 #include <fcntl.h>
90 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV)
91 #include <netinet/if_ether.h>
92 #endif
93 #include "afsutil.h"
94
95 #define uuid_memcmp(A,B,C)      memcmp(A,B,C)
96 #define uuid_memcpy(A,B,C)      memcpy(A,B,C)
97 #endif /* KERNEL */
98
99
100 typedef struct {
101     char eaddr[6];              /* 6 bytes of ethernet hardware address */
102 } uuid_address_t, *uuid_address_p_t;
103
104
105 typedef struct {
106     afs_uint32 lo;
107     afs_uint32 hi;
108 } uuid_time_t, *uuid_time_p_t;
109
110 static int uuid_get_address(uuid_address_p_t addr);
111 void uuid__get_os_time(uuid_time_t * os_time);
112
113 /*
114  * |<------------------------- 32 bits -------------------------->|
115  *
116  * +--------------------------------------------------------------+
117  * |                     low 32 bits of time                      |  0-3  .time_low
118  * +-------------------------------+-------------------------------
119  * |     mid 16 bits of time       |  4-5               .time_mid
120  * +-------+-----------------------+
121  * | vers. |   hi 12 bits of time  |  6-7               .time_hi_and_version
122  * +-------+-------+---------------+
123  * |Res|  clkSeqHi |  8                                 .clock_seq_hi_and_reserved
124  * +---------------+
125  * |   clkSeqLow   |  9                                 .clock_seq_low
126  * +---------------+----------...-----+
127  * |            node ID               |  8-16           .node
128  * +--------------------------...-----+
129  */
130
131 afsUUID afs_uuid_g_nil_uuid = { 0 };
132 static uuid_time_t time_now, time_last;
133 static u_short uuid_time_adjust, clock_seq;
134 static afs_uint32 rand_m, rand_ia, rand_ib, rand_irand, uuid_init_done = 0;
135
136 #define uuid_create_nil(uuid) memset(uuid, 0, sizeof(afsUUID))
137
138 afs_int32
139 afs_uuid_equal(afsUUID * u1, afsUUID * u2)
140 {
141     return (uuid_memcmp((void *)u1, (void *)u2, sizeof(afsUUID)) == 0);
142 }
143
144 afs_int32
145 afs_uuid_is_nil(afsUUID * u1)
146 {
147     if (!u1)
148         return 1;
149     return (uuid_memcmp
150             ((void *)u1, (void *)&afs_uuid_g_nil_uuid, sizeof(afsUUID)) == 0);
151 }
152
153 void
154 afs_htonuuid(afsUUID * uuidp)
155 {
156     uuidp->time_low = htonl(uuidp->time_low);
157     uuidp->time_mid = htons(uuidp->time_mid);
158     uuidp->time_hi_and_version = htons(uuidp->time_hi_and_version);
159 }
160
161 void
162 afs_ntohuuid(afsUUID * uuidp)
163 {
164     uuidp->time_low = ntohl(uuidp->time_low);
165     uuidp->time_mid = ntohs(uuidp->time_mid);
166     uuidp->time_hi_and_version = ntohs(uuidp->time_hi_and_version);
167 }
168
169 static u_short
170 true_random(void)
171 {
172     rand_m += 7;
173     rand_ia += 1907;
174     rand_ib += 73939;
175     if (rand_m >= 9973)
176         rand_m -= 9871;
177     if (rand_ia >= 99991)
178         rand_ia -= 89989;
179     if (rand_ib >= 224729)
180         rand_ib -= 96233;
181     rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib;
182     return (((rand_irand) >> 16) ^ (rand_irand & 0x3fff));
183 }
184
185
186 static afs_int32
187 time_cmp(uuid_time_p_t time1, uuid_time_p_t time2)
188 {
189     if (time1->hi < time2->hi)
190         return (-1);
191     if (time1->hi > time2->hi)
192         return (1);
193     if (time1->lo < time2->lo)
194         return (-1);
195     if (time1->lo > time2->lo)
196         return (1);
197     return (0);
198 }
199
200 /*
201  *    Converts a string UUID to binary representation.
202  */
203
204 #if !defined(KERNEL) && !defined(UKERNEL)
205 int
206 afsUUID_from_string(const char *str, afsUUID * uuid)
207 {
208     unsigned int time_low, time_mid, time_hi_and_version;
209     unsigned int clock_seq_hi_and_reserved, clock_seq_low;
210     unsigned int node[6];
211     int i;
212
213     i = sscanf(str, "%08x-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x",
214                &time_low, &time_mid, &time_hi_and_version,
215                &clock_seq_hi_and_reserved, &clock_seq_low, &node[0], &node[1],
216                &node[2], &node[3], &node[4], &node[5]);
217     if (i != 11)
218         return -1;
219
220     uuid->time_low = time_low;
221     uuid->time_mid = time_mid;
222     uuid->time_hi_and_version = time_hi_and_version;
223     uuid->clock_seq_hi_and_reserved = clock_seq_hi_and_reserved;
224     uuid->clock_seq_low = clock_seq_low;
225
226     for (i = 0; i < 6; i++)
227         uuid->node[i] = node[i];
228
229     return 0;
230 }
231
232 /*
233  *    Converts a UUID from binary representation to a string representation.
234  */
235
236 int
237 afsUUID_to_string(const afsUUID * uuid, char *str, size_t strsz)
238 {
239     snprintf(str, strsz, "%08x-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x",
240              uuid->time_low, uuid->time_mid, uuid->time_hi_and_version,
241              (unsigned char)uuid->clock_seq_hi_and_reserved,
242              (unsigned char)uuid->clock_seq_low, (unsigned char)uuid->node[0],
243              (unsigned char)uuid->node[1], (unsigned char)uuid->node[2],
244              (unsigned char)uuid->node[3], (unsigned char)uuid->node[4],
245              (unsigned char)uuid->node[5]);
246
247     return 0;
248 }
249 #endif
250
251 afs_int32
252 afs_uuid_create(afsUUID * uuid)
253 {
254     uuid_address_t eaddr;
255     afs_int32 got_no_time = 0, code;
256
257     if (!uuid_init_done) {
258         uuid_time_t t;
259         u_short *seedp, seed = 0;
260         rand_m = 971;;
261         rand_ia = 11113;
262         rand_ib = 104322;
263         rand_irand = 4181;
264         /*
265          * Generating our 'seed' value
266          *
267          * We start with the current time, but, since the resolution of clocks is
268          * system hardware dependent (eg. Ultrix is 10 msec.) and most likely
269          * coarser than our resolution (10 usec) we 'mixup' the bits by xor'ing
270          * all the bits together.  This will have the effect of involving all of
271          * the bits in the determination of the seed value while remaining system
272          * independent.  Then for good measure to ensure a unique seed when there
273          * are multiple processes creating UUID's on a system, we add in the PID.
274          */
275         uuid__get_os_time(&t);
276         seedp = (u_short *) (&t);
277         seed ^= *seedp++;
278         seed ^= *seedp++;
279         seed ^= *seedp++;
280         seed ^= *seedp++;
281 #if defined(KERNEL) && defined(AFS_XBSD_ENV)
282         rand_irand += seed + (afs_uint32) curproc->p_pid;
283 #else
284         rand_irand += seed + (afs_uint32) getpid();
285 #endif
286         uuid__get_os_time(&time_last);
287         clock_seq = true_random();
288 #ifdef AFS_NT40_ENV
289         if (afs_winsockInit() < 0) {
290             return WSAGetLastError();
291         }
292 #endif
293         uuid_init_done = 1;
294     }
295     if ((code = uuid_get_address(&eaddr)))
296         return code;            /* get our hardware network address */
297     do {
298         /* get the current time */
299         uuid__get_os_time(&time_now);
300         /*
301          * check that our clock hasn't gone backwards and handle it
302          *    accordingly with clock_seq
303          * check that we're not generating uuid's faster than we
304          *    can accommodate with our uuid_time_adjust fudge factor
305          */
306         if ((code = time_cmp(&time_now, &time_last)) == -1) {
307             /* A clock_seq value of 0 indicates that it hasn't been initialized. */
308             if (clock_seq == 0) {
309                 clock_seq = true_random();
310             }
311             clock_seq = (clock_seq + 1) & 0x3fff;
312             if (clock_seq == 0)
313                 clock_seq = clock_seq + 1;
314             uuid_time_adjust = 0;
315         } else if (code == 1) {
316             uuid_time_adjust = 0;
317         } else {
318             if (uuid_time_adjust == 0x7fff)     /* spin while we wait for the clock to tick */
319                 got_no_time = 1;
320             else
321                 uuid_time_adjust++;
322         }
323     } while (got_no_time);
324     time_last.lo = time_now.lo;
325     time_last.hi = time_now.hi;
326     if (uuid_time_adjust != 0) {
327         if (time_now.lo & 0x80000000) {
328             time_now.lo += uuid_time_adjust;
329             if (!(time_now.lo & 0x80000000))
330                 time_now.hi++;
331         } else
332             time_now.lo += uuid_time_adjust;
333     }
334     uuid->time_low = time_now.lo;
335     uuid->time_mid = time_now.hi & 0x0000ffff;
336     uuid->time_hi_and_version = (time_now.hi & 0x0fff0000) >> 16;
337     uuid->time_hi_and_version |= (1 << 12);
338     uuid->clock_seq_low = clock_seq & 0xff;
339     uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3f00) >> 8;
340     uuid->clock_seq_hi_and_reserved |= 0x80;
341     uuid_memcpy((void *)uuid->node, (void *)&eaddr, sizeof(uuid_address_t));
342     return 0;
343 }
344
345 u_short
346 afs_uuid_hash(afsUUID * uuid)
347 {
348     short c0 = 0, c1 = 0, x, y;
349     char *next_uuid = (char *)uuid;
350
351     /*
352      * For speed lets unroll the following loop:
353      *
354      *   for (i = 0; i < UUID_K_LENGTH; i++)
355      *   {
356      *       c0 = c0 + *next_uuid++;
357      *       c1 = c1 + c0;
358      *   }
359      */
360     c0 = c0 + *next_uuid++;
361     c1 = c1 + c0;
362     c0 = c0 + *next_uuid++;
363     c1 = c1 + c0;
364     c0 = c0 + *next_uuid++;
365     c1 = c1 + c0;
366     c0 = c0 + *next_uuid++;
367     c1 = c1 + c0;
368     c0 = c0 + *next_uuid++;
369     c1 = c1 + c0;
370     c0 = c0 + *next_uuid++;
371     c1 = c1 + c0;
372     c0 = c0 + *next_uuid++;
373     c1 = c1 + c0;
374     c0 = c0 + *next_uuid++;
375     c1 = c1 + c0;
376     c0 = c0 + *next_uuid++;
377     c1 = c1 + c0;
378     c0 = c0 + *next_uuid++;
379     c1 = c1 + c0;
380     c0 = c0 + *next_uuid++;
381     c1 = c1 + c0;
382     c0 = c0 + *next_uuid++;
383     c1 = c1 + c0;
384     c0 = c0 + *next_uuid++;
385     c1 = c1 + c0;
386     c0 = c0 + *next_uuid++;
387     c1 = c1 + c0;
388     c0 = c0 + *next_uuid++;
389     c1 = c1 + c0;
390     c0 = c0 + *next_uuid++;
391     c1 = c1 + c0;
392     /*  Calculate the value for "First octet" of the hash  */
393     x = -c1 % 255;
394     if (x < 0) {
395         x = x + 255;
396     }
397     /*  Calculate the value for "second octet" of the hash */
398     y = (c1 - c0) % 255;
399     if (y < 0) {
400         y = y + 255;
401     }
402     return ((y * 256) + x);
403 }
404
405 #ifdef KERNEL
406
407 extern struct interfaceAddr afs_cb_interface;
408
409 static int
410 uuid_get_address(uuid_address_p_t addr)
411 {
412     uuid_memcpy((void *)addr->eaddr, (void *)&afs_cb_interface.addr_in[0], 4);
413     addr->eaddr[4] = 0xaa;
414     addr->eaddr[5] = 0x77;
415     return 0;
416 }
417
418 void
419 uuid__get_os_time(uuid_time_t * os_time)
420 {
421     osi_timeval_t tp;
422
423     osi_GetTime(&tp);
424     os_time->hi = tp.tv_sec;
425     os_time->lo = tp.tv_usec * 10;
426 }
427
428 #else /* KERNEL */
429
430 char hostName1[128] = "localhost";
431 static int
432 uuid_get_address(uuid_address_p_t addr)
433 {
434     afs_int32 code;
435     afs_uint32 addr1;
436     struct hostent *he;
437
438     code = gethostname(hostName1, 64);
439     if (code) {
440         printf("gethostname() failed\n");
441 #ifdef AFS_NT40_ENV
442         return ENOENT;
443 #else
444         return errno;
445 #endif
446     }
447     he = gethostbyname(hostName1);
448     if (!he) {
449         printf("Can't find address for '%s'\n", hostName1);
450 #ifdef AFS_NT40_ENV
451         return ENOENT;
452 #else
453         return errno;
454 #endif
455     } else {
456         uuid_memcpy(&addr1, he->h_addr_list[0], 4);
457         addr1 = ntohl(addr1);
458         uuid_memcpy(addr->eaddr, &addr1, 4);
459         addr->eaddr[4] = 0xaa;
460         addr->eaddr[5] = 0x77;
461 #ifdef  UUID_DEBUG
462         printf("uuid_get_address: %02x-%02x-%02x-%02x-%02x-%02x\n",
463                addr->eaddr[0], addr->eaddr[1], addr->eaddr[2], addr->eaddr[3],
464                addr->eaddr[4], addr->eaddr[5]);
465 #endif
466     }
467     return 0;
468 }
469
470 void
471 uuid__get_os_time(uuid_time_t * os_time)
472 {
473     struct timeval tp;
474
475     if (gettimeofday(&tp, NULL)) {
476         perror("uuid__get_time");
477         exit(-1);
478     }
479     os_time->hi = tp.tv_sec;
480     os_time->lo = tp.tv_usec * 10;
481 }
482
483 #endif /* KERNEL */