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