603961086fe4c502122a0412b83884b033327212
[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 #include <roken.h>
51 #endif
52
53
54 #ifdef KERNEL
55 #include "afs/sysincludes.h"
56 #include "afsincludes.h"
57 #else /* KERNEL */
58 #include <stdio.h>
59 #include <errno.h>
60 #include <string.h>
61 #ifdef AFS_NT40_ENV
62 #include <rpc.h>
63 #include <winsock2.h>
64 #include <process.h>
65 #else
66 #include <sys/file.h>
67 #include <netinet/in.h>
68 #include <netdb.h>
69 #include <sys/ioctl.h>
70 #include <sys/socket.h>
71 #ifndef ITIMER_REAL
72 #include <sys/time.h>
73 #endif /* ITIMER_REAL */
74 #include <net/if.h>
75 #ifdef HAVE_UNISTD_H
76 #include <unistd.h>
77 #endif
78 #include <stdlib.h>
79 #endif
80 #include <sys/stat.h>
81 #include <fcntl.h>
82 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
83 #include <netinet/if_ether.h>
84 #endif
85 #include "afsutil.h"
86 #endif /* KERNEL */
87
88
89 typedef struct {
90     char eaddr[6];              /* 6 bytes of ethernet hardware address */
91 } uuid_address_t, *uuid_address_p_t;
92
93
94 typedef struct {
95     afs_uint32 lo;
96     afs_uint32 hi;
97 } uuid_time_t, *uuid_time_p_t;
98
99 static int uuid_get_address(uuid_address_p_t addr);
100 void uuid__get_os_time(uuid_time_t * os_time);
101
102 /*
103  * |<------------------------- 32 bits -------------------------->|
104  *
105  * +--------------------------------------------------------------+
106  * |                     low 32 bits of time                      |  0-3  .time_low
107  * +-------------------------------+-------------------------------
108  * |     mid 16 bits of time       |  4-5               .time_mid
109  * +-------+-----------------------+
110  * | vers. |   hi 12 bits of time  |  6-7               .time_hi_and_version
111  * +-------+-------+---------------+
112  * |Res|  clkSeqHi |  8                                 .clock_seq_hi_and_reserved
113  * +---------------+
114  * |   clkSeqLow   |  9                                 .clock_seq_low
115  * +---------------+----------...-----+
116  * |            node ID               |  8-16           .node
117  * +--------------------------...-----+
118  */
119
120 afsUUID afs_uuid_g_nil_uuid = { 0 };
121 static uuid_time_t time_now, time_last;
122 static u_short uuid_time_adjust, clock_seq;
123 static afs_uint32 rand_m, rand_ia, rand_ib, rand_irand, uuid_init_done = 0;
124
125 #define uuid_create_nil(uuid) memset(uuid, 0, sizeof(afsUUID))
126
127 afs_int32
128 afs_uuid_equal(afsUUID * u1, afsUUID * u2)
129 {
130     return (memcmp(u1, u2, sizeof(afsUUID)) == 0);
131 }
132
133 afs_int32
134 afs_uuid_is_nil(afsUUID * u1)
135 {
136     if (!u1)
137         return 1;
138     return afs_uuid_equal(u1, &afs_uuid_g_nil_uuid);
139 }
140
141 void
142 afs_htonuuid(afsUUID * uuidp)
143 {
144     uuidp->time_low = htonl(uuidp->time_low);
145     uuidp->time_mid = htons(uuidp->time_mid);
146     uuidp->time_hi_and_version = htons(uuidp->time_hi_and_version);
147 }
148
149 void
150 afs_ntohuuid(afsUUID * uuidp)
151 {
152     uuidp->time_low = ntohl(uuidp->time_low);
153     uuidp->time_mid = ntohs(uuidp->time_mid);
154     uuidp->time_hi_and_version = ntohs(uuidp->time_hi_and_version);
155 }
156
157 static u_short
158 true_random(void)
159 {
160     rand_m += 7;
161     rand_ia += 1907;
162     rand_ib += 73939;
163     if (rand_m >= 9973)
164         rand_m -= 9871;
165     if (rand_ia >= 99991)
166         rand_ia -= 89989;
167     if (rand_ib >= 224729)
168         rand_ib -= 96233;
169     rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib;
170     return (((rand_irand) >> 16) ^ (rand_irand & 0x3fff));
171 }
172
173
174 static afs_int32
175 time_cmp(uuid_time_p_t time1, uuid_time_p_t time2)
176 {
177     if (time1->hi < time2->hi)
178         return (-1);
179     if (time1->hi > time2->hi)
180         return (1);
181     if (time1->lo < time2->lo)
182         return (-1);
183     if (time1->lo > time2->lo)
184         return (1);
185     return (0);
186 }
187
188 /*
189  *    Converts a string UUID to binary representation.
190  */
191
192 #if !defined(KERNEL) && !defined(UKERNEL)
193 int
194 afsUUID_from_string(const char *str, afsUUID * uuid)
195 {
196     unsigned int time_low, time_mid, time_hi_and_version;
197     unsigned int clock_seq_hi_and_reserved, clock_seq_low;
198     unsigned int node[6];
199     int i;
200
201     i = sscanf(str, "%08x-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x",
202                &time_low, &time_mid, &time_hi_and_version,
203                &clock_seq_hi_and_reserved, &clock_seq_low, &node[0], &node[1],
204                &node[2], &node[3], &node[4], &node[5]);
205     if (i != 11)
206         return -1;
207
208     uuid->time_low = time_low;
209     uuid->time_mid = time_mid;
210     uuid->time_hi_and_version = time_hi_and_version;
211     uuid->clock_seq_hi_and_reserved = clock_seq_hi_and_reserved;
212     uuid->clock_seq_low = clock_seq_low;
213
214     for (i = 0; i < 6; i++)
215         uuid->node[i] = node[i];
216
217     return 0;
218 }
219
220 /*
221  *    Converts a UUID from binary representation to a string representation.
222  */
223
224 int
225 afsUUID_to_string(const afsUUID * uuid, char *str, size_t strsz)
226 {
227     snprintf(str, strsz, "%08x-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x",
228              uuid->time_low, uuid->time_mid, uuid->time_hi_and_version,
229              (unsigned char)uuid->clock_seq_hi_and_reserved,
230              (unsigned char)uuid->clock_seq_low, (unsigned char)uuid->node[0],
231              (unsigned char)uuid->node[1], (unsigned char)uuid->node[2],
232              (unsigned char)uuid->node[3], (unsigned char)uuid->node[4],
233              (unsigned char)uuid->node[5]);
234
235     return 0;
236 }
237 #endif
238
239 afs_int32
240 afs_uuid_create(afsUUID * uuid)
241 {
242 #ifdef AFS_NT40_ENV
243     UuidCreate((UUID *) uuid);
244 #else /* AFS_NT40_ENV */
245     uuid_address_t eaddr;
246     afs_int32 got_no_time = 0, code;
247
248     if (!uuid_init_done) {
249         uuid_time_t t;
250         u_short seedp[4], seed = 0;
251         rand_m = 971;;
252         rand_ia = 11113;
253         rand_ib = 104322;
254         rand_irand = 4181;
255         /*
256          * Generating our 'seed' value
257          *
258          * We start with the current time, but, since the resolution of clocks is
259          * system hardware dependent (eg. Ultrix is 10 msec.) and most likely
260          * coarser than our resolution (10 usec) we 'mixup' the bits by xor'ing
261          * all the bits together.  This will have the effect of involving all of
262          * the bits in the determination of the seed value while remaining system
263          * independent.  Then for good measure to ensure a unique seed when there
264          * are multiple processes creating UUID's on a system, we add in the PID.
265          */
266         uuid__get_os_time(&t);
267         memcpy(&seedp, &t, sizeof(seedp));
268         seed ^= seedp[0];
269         seed ^= seedp[1];
270         seed ^= seedp[2];
271         seed ^= seedp[3];
272 #if defined(KERNEL) && defined(AFS_XBSD_ENV)
273         rand_irand += seed + (afs_uint32) curproc->p_pid;
274 #elif defined(UKERNEL)
275         rand_irand += seed + (afs_uint32) osi_getpid();
276 #else
277         rand_irand += seed + (afs_uint32) getpid();
278 #endif
279         uuid__get_os_time(&time_last);
280         clock_seq = true_random();
281 #ifdef AFS_NT40_ENV
282         if (afs_winsockInit() < 0) {
283             return WSAGetLastError();
284         }
285 #endif
286         uuid_init_done = 1;
287     }
288     if ((code = uuid_get_address(&eaddr)))
289         return code;            /* get our hardware network address */
290     do {
291         /* get the current time */
292         uuid__get_os_time(&time_now);
293         /*
294          * check that our clock hasn't gone backwards and handle it
295          *    accordingly with clock_seq
296          * check that we're not generating uuid's faster than we
297          *    can accommodate with our uuid_time_adjust fudge factor
298          */
299         if ((code = time_cmp(&time_now, &time_last)) == -1) {
300             /* A clock_seq value of 0 indicates that it hasn't been initialized. */
301             if (clock_seq == 0) {
302                 clock_seq = true_random();
303             }
304             clock_seq = (clock_seq + 1) & 0x3fff;
305             if (clock_seq == 0)
306                 clock_seq = clock_seq + 1;
307             uuid_time_adjust = 0;
308         } else if (code == 1) {
309             uuid_time_adjust = 0;
310         } else {
311             if (uuid_time_adjust == 0x7fff)     /* spin while we wait for the clock to tick */
312                 got_no_time = 1;
313             else
314                 uuid_time_adjust++;
315         }
316     } while (got_no_time);
317     time_last.lo = time_now.lo;
318     time_last.hi = time_now.hi;
319     if (uuid_time_adjust != 0) {
320         if (time_now.lo & 0x80000000) {
321             time_now.lo += uuid_time_adjust;
322             if (!(time_now.lo & 0x80000000))
323                 time_now.hi++;
324         } else
325             time_now.lo += uuid_time_adjust;
326     }
327     uuid->time_low = time_now.lo;
328     uuid->time_mid = time_now.hi & 0x0000ffff;
329     uuid->time_hi_and_version = (time_now.hi & 0x0fff0000) >> 16;
330     uuid->time_hi_and_version |= (1 << 12);
331     uuid->clock_seq_low = clock_seq & 0xff;
332     uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3f00) >> 8;
333     uuid->clock_seq_hi_and_reserved |= 0x80;
334     memcpy(uuid->node, &eaddr, sizeof(uuid_address_t));
335 #endif /* AFS_NT40_ENV */
336     return 0;
337 }
338
339 u_short
340 afs_uuid_hash(afsUUID * uuid)
341 {
342     short c0 = 0, c1 = 0, x, y;
343     char *next_uuid = (char *)uuid;
344
345     /*
346      * For speed lets unroll the following loop:
347      *
348      *   for (i = 0; i < UUID_K_LENGTH; i++)
349      *   {
350      *       c0 = c0 + *next_uuid++;
351      *       c1 = c1 + c0;
352      *   }
353      */
354     c0 = c0 + *next_uuid++;
355     c1 = c1 + c0;
356     c0 = c0 + *next_uuid++;
357     c1 = c1 + c0;
358     c0 = c0 + *next_uuid++;
359     c1 = c1 + c0;
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     /*  Calculate the value for "First octet" of the hash  */
387     x = -c1 % 255;
388     if (x < 0) {
389         x = x + 255;
390     }
391     /*  Calculate the value for "second octet" of the hash */
392     y = (c1 - c0) % 255;
393     if (y < 0) {
394         y = y + 255;
395     }
396     return ((y * 256) + x);
397 }
398
399 #ifdef KERNEL
400
401 extern struct interfaceAddr afs_cb_interface;
402
403 static int
404 uuid_get_address(uuid_address_p_t addr)
405 {
406     memcpy(addr->eaddr, &afs_cb_interface.addr_in[0], 4);
407     addr->eaddr[4] = 0xaa;
408     addr->eaddr[5] = 0x77;
409     return 0;
410 }
411
412 void
413 uuid__get_os_time(uuid_time_t * os_time)
414 {
415     osi_timeval_t tp;
416
417     osi_GetTime(&tp);
418     os_time->hi = tp.tv_sec;
419     os_time->lo = tp.tv_usec * 10;
420 }
421
422 #else /* KERNEL */
423
424 char hostName1[128] = "localhost";
425 static int
426 uuid_get_address(uuid_address_p_t addr)
427 {
428     afs_int32 code;
429     afs_uint32 addr1;
430     struct hostent *he;
431
432     code = gethostname(hostName1, 64);
433     if (code) {
434         printf("gethostname() failed\n");
435 #ifdef AFS_NT40_ENV
436         return ENOENT;
437 #else
438         return errno;
439 #endif
440     }
441     he = gethostbyname(hostName1);
442     if (!he) {
443         printf("Can't find address for '%s'\n", hostName1);
444 #ifdef AFS_NT40_ENV
445         return ENOENT;
446 #else
447         return errno;
448 #endif
449     } else {
450         memcpy(&addr1, he->h_addr_list[0], 4);
451         addr1 = ntohl(addr1);
452         memcpy(addr->eaddr, &addr1, 4);
453         addr->eaddr[4] = 0xaa;
454         addr->eaddr[5] = 0x77;
455 #ifdef  UUID_DEBUG
456         printf("uuid_get_address: %02x-%02x-%02x-%02x-%02x-%02x\n",
457                addr->eaddr[0], addr->eaddr[1], addr->eaddr[2], addr->eaddr[3],
458                addr->eaddr[4], addr->eaddr[5]);
459 #endif
460     }
461     return 0;
462 }
463
464 void
465 uuid__get_os_time(uuid_time_t * os_time)
466 {
467     struct timeval tp;
468
469     if (gettimeofday(&tp, NULL)) {
470         perror("uuid__get_time");
471         exit(-1);
472     }
473     os_time->hi = tp.tv_sec;
474     os_time->lo = tp.tv_usec * 10;
475 }
476
477 #endif /* KERNEL */