fa2a4a6bd38dbe864a32062f77de9facc24282c8
[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 #ifdef KERNEL
11 #include "../afs/param.h"
12 #include "../afs/sysincludes.h"
13 #include "../afs/afsincludes.h"
14 #define uuid_memcmp(A,B,C)      bcmp(A,B,C)
15 #define uuid_memcpy(A,B,C)      bcopy(B,A,C)
16 #else /* KERNEL */
17 #include <afs/param.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #include <process.h>
23 #else
24 #include <sys/file.h>
25 #include <netinet/in.h>
26 #include <netdb.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
29 #ifndef ITIMER_REAL
30 #include <sys/time.h>
31 #endif /* ITIMER_REAL */
32 #include <net/if.h>
33 #endif
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV)
37 #include <netinet/if_ether.h>
38 #endif
39 #include "afsutil.h"
40
41 #define uuid_memcmp(A,B,C)      memcmp(A,B,C)
42 #define uuid_memcpy(A,B,C)      memcpy(A,B,C)
43 #endif /* KERNEL */
44
45
46 typedef struct {
47     char eaddr[6];      /* 6 bytes of ethernet hardware address */
48 } uuid_address_t, *uuid_address_p_t;
49
50
51 typedef struct {
52     afs_uint32  lo;
53     afs_uint32  hi;
54 } uuid_time_t, *uuid_time_p_t;
55
56 static int uuid_get_address (uuid_address_p_t addr);
57 void uuid__get_os_time (uuid_time_t *os_time);
58
59 /*
60  * |<------------------------- 32 bits -------------------------->|
61  *
62  * +--------------------------------------------------------------+
63  * |                     low 32 bits of time                      |  0-3  .time_low
64  * +-------------------------------+-------------------------------
65  * |     mid 16 bits of time       |  4-5               .time_mid
66  * +-------+-----------------------+
67  * | vers. |   hi 12 bits of time  |  6-7               .time_hi_and_version
68  * +-------+-------+---------------+
69  * |Res|  clkSeqHi |  8                                 .clock_seq_hi_and_reserved
70  * +---------------+
71  * |   clkSeqLow   |  9                                 .clock_seq_low
72  * +---------------+----------...-----+
73  * |            node ID               |  8-16           .node
74  * +--------------------------...-----+
75  */
76
77 afsUUID afs_uuid_g_nil_uuid = { 0 };
78 static uuid_time_t time_now, time_last;
79 static u_short uuid_time_adjust, clock_seq;
80 static afs_uint32 rand_m, rand_ia, rand_ib, rand_irand, uuid_init_done = 0;
81
82 #define uuid_create_nil(uuid) memset(uuid, 0, sizeof(afsUUID))
83 afs_uuid_equal(u1, u2) afsUUID *u1, *u2;  { return(uuid_memcmp((void *)u1, (void *)u2, sizeof (afsUUID)) == 0); }
84 afs_uuid_is_nil(u1) afsUUID *u1; { 
85     if (!u1) return 1;
86     return(uuid_memcmp((void *)u1, (void *)&afs_uuid_g_nil_uuid, sizeof (afsUUID)) == 0); 
87 }
88
89
90 void afs_htonuuid(uuidp)
91 afsUUID *uuidp; {
92     uuidp->time_low = htonl(uuidp->time_low);
93     uuidp->time_mid = htons(uuidp->time_mid);
94     uuidp->time_hi_and_version = htons(uuidp->time_hi_and_version);
95 }
96
97 void afs_ntohuuid(uuidp)
98 afsUUID *uuidp; {
99     uuidp->time_low = ntohl(uuidp->time_low);
100     uuidp->time_mid = ntohs(uuidp->time_mid);
101     uuidp->time_hi_and_version = ntohs(uuidp->time_hi_and_version);
102 }
103  
104 static u_short true_random () {
105     rand_m += 7;
106     rand_ia += 1907;
107     rand_ib += 73939;
108     if (rand_m >= 9973) rand_m -= 9871;
109     if (rand_ia >= 99991) rand_ia -= 89989;
110     if (rand_ib >= 224729) rand_ib -= 96233;
111     rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib;
112     return (((rand_irand) >> 16) ^ (rand_irand & 0x3fff));
113 }
114
115
116 static afs_int32 time_cmp (time1, time2)
117 uuid_time_p_t           time1;
118 uuid_time_p_t           time2; {
119     if (time1->hi < time2->hi) return (-1);
120     if (time1->hi > time2->hi) return (1);
121     if (time1->lo < time2->lo) return (-1);
122     if (time1->lo > time2->lo) return (1);
123     return (0);
124 }
125
126 afs_uuid_create (uuid)
127 afsUUID *uuid; {
128     uuid_address_t eaddr;
129     afs_int32 got_no_time = 0, code;
130
131     if (!uuid_init_done) {
132         uuid_time_t t;
133         u_short *seedp, seed=0;
134         rand_m = 971;;
135         rand_ia = 11113;
136         rand_ib = 104322;
137         rand_irand = 4181;
138         /*
139          * Generating our 'seed' value
140          *
141          * We start with the current time, but, since the resolution of clocks is
142          * system hardware dependent (eg. Ultrix is 10 msec.) and most likely
143          * coarser than our resolution (10 usec) we 'mixup' the bits by xor'ing
144          * all the bits together.  This will have the effect of involving all of
145          * the bits in the determination of the seed value while remaining system
146          * independent.  Then for good measure to ensure a unique seed when there
147          * are multiple processes creating UUID's on a system, we add in the PID.
148          */
149         uuid__get_os_time(&t);
150         seedp = (u_short *)(&t);
151         seed ^= *seedp++;
152         seed ^= *seedp++;
153         seed ^= *seedp++;
154         seed ^= *seedp++;
155         rand_irand += seed + (afs_uint32)getpid();
156         uuid__get_os_time (&time_last);
157         clock_seq = true_random();
158 #ifdef AFS_NT40_ENV
159         if (afs_winsockInit()<0) {
160             return WSAGetLastError();
161         }
162 #endif  
163         uuid_init_done = 1;
164     }
165     if (code = uuid_get_address (&eaddr)) return code;     /* get our hardware network address */
166     do {
167         /* get the current time */
168         uuid__get_os_time (&time_now);
169         /*
170          * check that our clock hasn't gone backwards and handle it
171          *    accordingly with clock_seq
172          * check that we're not generating uuid's faster than we
173          *    can accommodate with our uuid_time_adjust fudge factor
174          */
175         if ((code = time_cmp (&time_now, &time_last)) == -1) {
176             /* A clock_seq value of 0 indicates that it hasn't been initialized. */
177             if (clock_seq == 0) {
178                 clock_seq = true_random();
179             }
180             clock_seq = (clock_seq + 1) & 0x3fff;
181             if (clock_seq == 0) clock_seq = clock_seq + 1;
182             uuid_time_adjust = 0;
183         } else if (code == 1) {
184             uuid_time_adjust = 0;
185         } else {
186             if (uuid_time_adjust == 0x7fff) /* spin while we wait for the clock to tick */
187                 got_no_time = 1;
188             else
189                 uuid_time_adjust++;
190         }
191     } while (got_no_time);
192     time_last.lo = time_now.lo;
193     time_last.hi = time_now.hi;
194     if (uuid_time_adjust != 0) {
195         if (time_now.lo & 0x80000000) {
196             time_now.lo += uuid_time_adjust;
197             if (!(time_now.lo & 0x80000000)) time_now.hi++;
198         } else
199             time_now.lo += uuid_time_adjust;
200     }
201     uuid->time_low = time_now.lo;
202     uuid->time_mid = time_now.hi & 0x0000ffff;
203     uuid->time_hi_and_version = (time_now.hi & 0x0fff0000) >> 16;
204     uuid->time_hi_and_version |= (1 << 12);
205     uuid->clock_seq_low = clock_seq & 0xff;
206     uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3f00) >> 8;
207     uuid->clock_seq_hi_and_reserved |= 0x80;
208     uuid_memcpy ((void *)uuid->node, (void *)&eaddr, sizeof (uuid_address_t));
209     return 0;
210 }
211
212 u_short afs_uuid_hash (uuid)
213 afsUUID *uuid; {
214     short               c0=0, c1=0, x, y;
215     char             *next_uuid = (char *) uuid;
216
217     /*
218      * For speed lets unroll the following loop:
219      *
220      *   for (i = 0; i < UUID_K_LENGTH; i++)
221      *   {
222      *       c0 = c0 + *next_uuid++;
223      *       c1 = c1 + c0;
224      *   }
225      */
226     c0 = c0 + *next_uuid++;
227     c1 = c1 + c0;
228     c0 = c0 + *next_uuid++;
229     c1 = c1 + c0;
230     c0 = c0 + *next_uuid++;
231     c1 = c1 + c0;
232     c0 = c0 + *next_uuid++;
233     c1 = c1 + c0;
234     c0 = c0 + *next_uuid++;
235     c1 = c1 + c0;
236     c0 = c0 + *next_uuid++;
237     c1 = c1 + c0;
238     c0 = c0 + *next_uuid++;
239     c1 = c1 + c0;
240     c0 = c0 + *next_uuid++;
241     c1 = c1 + c0;
242     c0 = c0 + *next_uuid++;
243     c1 = c1 + c0;
244     c0 = c0 + *next_uuid++;
245     c1 = c1 + c0;
246     c0 = c0 + *next_uuid++;
247     c1 = c1 + c0;
248     c0 = c0 + *next_uuid++;
249     c1 = c1 + c0;
250     c0 = c0 + *next_uuid++;
251     c1 = c1 + c0;
252     c0 = c0 + *next_uuid++;
253     c1 = c1 + c0;
254     c0 = c0 + *next_uuid++;
255     c1 = c1 + c0;
256     c0 = c0 + *next_uuid++;
257     c1 = c1 + c0;
258     /*  Calculate the value for "First octet" of the hash  */
259     x = -c1 % 255;
260     if (x < 0) {
261         x = x + 255;
262     }
263     /*  Calculate the value for "second octet" of the hash */
264     y = (c1 - c0) % 255;
265     if (y < 0) {
266         y = y + 255;
267     }
268     return ((y * 256) + x);
269 }
270
271 #ifdef KERNEL
272
273 extern struct interfaceAddr afs_cb_interface;
274
275 static int uuid_get_address (uuid_address_p_t addr)
276 {
277     uuid_memcpy((void *)addr->eaddr, (void *)&afs_cb_interface.addr_in[0], 4);
278     addr->eaddr[4] = 0xaa;
279     addr->eaddr[5] = 0x77;
280     return 0;
281 }
282
283 void uuid__get_os_time (uuid_time_t *os_time)
284 {
285     struct timeval      tp;
286
287     osi_GetTime(&tp);
288     os_time->hi = tp.tv_sec;
289     os_time->lo = tp.tv_usec*10;
290 }
291
292 #else /* KERNEL */
293
294 char hostName1[128] = "localhost";
295 static int uuid_get_address (uuid_address_p_t addr)
296 {
297     afs_int32 code, addr1;
298     struct hostent *he;
299
300     code = gethostname(hostName1, 64);
301     if (code) {
302         printf("gethostname() failed\n");
303 #ifdef AFS_NT40_ENV
304         return ENOENT;
305 #else
306         return errno;
307 #endif
308     }
309     he = gethostbyname(hostName1);
310     if (!he) {
311         printf("Can't find address for '%s'\n", hostName1);
312 #ifdef AFS_NT40_ENV
313         return ENOENT;
314 #else
315         return errno;
316 #endif
317     } else {
318       uuid_memcpy(&addr1, he->h_addr_list[0], 4);
319       addr1 = ntohl(addr1);
320       uuid_memcpy(addr->eaddr,  &addr1, 4);
321       addr->eaddr[4] = 0xaa;
322       addr->eaddr[5] = 0x77;
323 #ifdef  UUID_DEBUG
324       printf ("uuid_get_address: %02x-%02x-%02x-%02x-%02x-%02x\n",
325                 addr->eaddr[0], addr->eaddr[1], addr->eaddr[2],
326                 addr->eaddr[3], addr->eaddr[4], addr->eaddr[5]);
327 #endif
328     }
329     return 0;
330 }
331
332 void uuid__get_os_time (uuid_time_t *os_time)
333 {
334     struct timeval      tp;
335
336     if (gettimeofday (&tp, (struct timezone *) 0)) {
337         perror ("uuid__get_time");
338         exit (-1);
339     }
340     os_time->hi = tp.tv_sec;
341     os_time->lo = tp.tv_usec*10;
342 }
343
344 #endif /* KERNEL */