source: trunk/src/rpcrt4/uuid.cpp@ 3307

Last change on this file since 3307 was 3307, checked in by davidr, 25 years ago

RPCRT4: Remote Procedure Call Runtime

File size: 17.2 KB
Line 
1/* $Id: uuid.cpp,v 1.1 2000-04-02 22:02:59 davidr Exp $ */
2/*
3 * RPCRT4 library
4 * UUID manipulation
5 * Partially based on OSF sources (see below)
6 *
7 * 2000/02/05
8 *
9 * Copyright 2000 David J. Raison
10 * 2000 Edgar Buerkle
11 *
12 * Project Odin Software License can be found in LICENSE.TXT
13 *
14 */
15/*
16 *
17 * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC.
18 * (c) Copyright 1989 HEWLETT-PACKARD COMPANY
19 * (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION
20 * To anyone who acknowledges that this file is provided "AS IS"
21 * without any express or implied warranty:
22 * permission to use, copy, modify, and distribute this
23 * file for any purpose is hereby granted without fee, provided that
24 * the above copyright notices and this notice appears in all source
25 * code copies, and that none of the names of Open Software
26 * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment
27 * Corporation be used in advertising or publicity pertaining to
28 * distribution of the software without specific, written prior
29 * permission. Neither Open Software Foundation, Inc., Hewlett-
30 * Packard Company, nor Digital Equipment Corporation makes any
31 * representations about the suitability of this software for any
32 * purpose.
33 *
34 */
35
36#include "rpcrt4.h"
37#include "uuidp.h"
38
39#include "io.h"
40#include "sys\timeb.h"
41
42#include <sys\socket.h>
43#include <sys\ioctl.h>
44#include <netdb.h>
45#include <netinet\in.h>
46#include <netinet\tcp.h>
47#undef interface
48#include <net\if.h>
49#include <netinet\if_ether.h>
50#include <nerrno.h>
51#include <sys\time.h>
52
53ULONG WINAPI RtlExtendedIntegerMultiply(LARGE_INTEGER factor1, INT factor2);
54ULONG WINAPI RtlLargeIntegerAdd(LARGE_INTEGER arg1, LARGE_INTEGER arg2);
55
56extern "C" ULONG getEAX();
57extern "C" ULONG getEDX();
58
59static UUID uuid_nil = { 0 };
60static unsigned char uuid_addr[6];
61
62// ----------------------------------------------------------------------
63// UuidInit
64// Init the Uuid subsystem (i.e. retrieve & cache the eth. addr)
65// ----------------------------------------------------------------------
66extern void UuidInit(void )
67{
68 struct ifmib ifm = {0};
69 int fFound = FALSE;
70 int sd;
71 int ii;
72
73 // Ensure that uuid_nil is initialised.
74 memset(&uuid_nil, 0, sizeof(uuid_nil));
75
76 // retrieve & cache the eth. addr
77
78 /* BSD 4.4 defines the size of an ifreq to be
79 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
80 * However, under earlier systems, sa_len isn't present, so
81 * the size is just sizeof(struct ifreq)
82 */
83 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
84 if (sd > 0)
85 {
86 if (ioctl(sd, SIOSTATIF42, (char *)&ifm, sizeof(ifm)) >= 0)
87 {
88 for(ii = 0; ii < ifm.ifNumber; ii++)
89 {
90 if (!ifm.iftable[ii].ifPhysAddr[0] && !ifm.iftable[ii].ifPhysAddr[1] &&
91 !ifm.iftable[ii].ifPhysAddr[2] && !ifm.iftable[ii].ifPhysAddr[3] &&
92 !ifm.iftable[ii].ifPhysAddr[4] && !ifm.iftable[ii].ifPhysAddr[5])
93 continue;
94 fFound = TRUE;
95 memcpy(uuid_addr, (unsigned char *)&ifm.iftable[ii].ifPhysAddr, 6);
96 }
97 }
98 close(sd);
99 }
100
101 if (!fFound)
102 {
103 /* if we can't find the physical net address use random numbers */
104 /* set the multicast bit to prevent conflicts with real cards */
105
106 uuid_addr[0] = (rand() & 0xff) | 0x80;
107 uuid_addr[1] = rand() & 0xff;
108 uuid_addr[2] = rand() & 0xff;
109 uuid_addr[3] = rand() & 0xff;
110 uuid_addr[4] = rand() & 0xff;
111 uuid_addr[5] = rand() & 0xff;
112 }
113}
114
115// ----------------------------------------------------------------------
116// gettimeofday
117// ----------------------------------------------------------------------
118static int
119gettimeofday(struct timeval* tp, void* tzp)
120{
121 struct timeb tb;
122
123 ftime(&tb);
124 tp->tv_sec = tb.time;
125 tp->tv_usec = tb.millitm * 1000;
126
127 return 0;
128}
129
130// ----------------------------------------------------------------------
131// UuidCreate
132// Implemented according the DCE specification for UUID generation.
133// Code is based upon uuid library in e2fsprogs by Theodore Ts'o.
134// Copyright (C) 1996, 1997 Theodore Ts'o.
135//
136// Returns
137// S_OK if successful.
138// ----------------------------------------------------------------------
139RPCRTAPI
140RPC_STATUS
141RPC_ENTRY
142UuidCreate (
143 OUT UUID __RPC_FAR * pUuid
144 )
145{
146 static int adjustment = 0;
147 static struct timeval last = {0, 0};
148 static UINT16 clock_seq;
149 struct timeval tv;
150 LARGE_INTEGER clock_reg={0};
151 LARGE_INTEGER clock_reg_tmp={0};
152 UINT clock_high;
153 UINT clock_low;
154 UINT16 temp_clock_seq;
155 UINT16 temp_clock_mid;
156 UINT16 temp_clock_hi_and_version;
157 BOOL got_no_time;
158
159 dprintf(("RPCRT4: %s", __FUNCTION__));
160
161 /* The OS/2 gettimeofday has a >1ms granularity (~17 bps) */
162 #define MAX_ADJUSTMENT 10000
163
164 do
165 {
166 got_no_time = FALSE;
167
168 gettimeofday(&tv, 0);
169 if ((last.tv_sec == 0) && (last.tv_usec == 0))
170 {
171 clock_seq = ((rand() & 0xff) << 8) + (rand() & 0xff);
172 clock_seq &= 0x1FFF;
173 last = tv;
174 last.tv_sec--;
175 }
176 if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) &&
177 (tv.tv_usec < last.tv_usec)))
178 {
179 clock_seq = (clock_seq+1) & 0x1FFF;
180 adjustment = 0;
181 }
182 else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec))
183 {
184 if (adjustment >= MAX_ADJUSTMENT)
185 {
186 got_no_time = TRUE;
187 Sleep(1); // Allow someone else to run.
188 }
189 else
190 adjustment++;
191 }
192 else
193 {
194 adjustment = 0;
195 last = tv; // ><EB missing in wine and maybe(not tested) in ef2prog
196 }
197
198 } while(got_no_time);
199
200 clock_reg_tmp.LowPart = tv.tv_usec*10 + adjustment;
201 clock_reg_tmp.HighPart = tv.tv_sec;
202
203 RtlExtendedIntegerMultiply(clock_reg_tmp, 10000000);
204 clock_reg.LowPart = getEAX();
205 clock_reg.HighPart = getEDX();
206
207 RtlLargeIntegerAdd(clock_reg, clock_reg_tmp );
208 clock_reg.LowPart = getEAX();
209 clock_reg.HighPart = getEDX();
210
211 clock_reg_tmp.LowPart = 0x13814000;
212 clock_reg_tmp.HighPart = 0x01B21DD2;
213 RtlLargeIntegerAdd(clock_reg, clock_reg_tmp );
214 clock_reg.LowPart = getEAX();
215 clock_reg.HighPart = getEDX();
216
217 clock_high = clock_reg.HighPart;
218 clock_low = clock_reg.LowPart;
219
220 temp_clock_seq = clock_seq | 0x8000;
221 temp_clock_mid = (UINT16)clock_high;
222 temp_clock_hi_and_version = (clock_high >> 16) | 0x1000;
223
224 /* pack the information into the GUID structure */
225 ((unsigned char*)&pUuid->Data1)[3] = (unsigned char)clock_low;
226 clock_low >>= 8;
227 ((unsigned char*)&pUuid->Data1)[2] = (unsigned char)clock_low;
228 clock_low >>= 8;
229 ((unsigned char*)&pUuid->Data1)[1] = (unsigned char)clock_low;
230 clock_low >>= 8;
231 ((unsigned char*)&pUuid->Data1)[0] = (unsigned char)clock_low;
232
233 ((unsigned char*)&pUuid->Data2)[1] = (unsigned char)temp_clock_mid;
234 temp_clock_mid >>= 8;
235 ((unsigned char*)&pUuid->Data2)[0] = (unsigned char)temp_clock_mid;
236
237 ((unsigned char*)&pUuid->Data3)[1] = (unsigned char)temp_clock_hi_and_version;
238 temp_clock_hi_and_version >>= 8;
239 ((unsigned char*)&pUuid->Data3)[0] = (unsigned char)temp_clock_hi_and_version;
240
241 ((unsigned char*)pUuid->Data4)[1] = (unsigned char)temp_clock_seq;
242 temp_clock_seq >>= 8;
243 ((unsigned char*)pUuid->Data4)[0] = (unsigned char)temp_clock_seq;
244
245 ((unsigned char*)pUuid->Data4)[2] = uuid_addr[0];
246 ((unsigned char*)pUuid->Data4)[3] = uuid_addr[1];
247 ((unsigned char*)pUuid->Data4)[4] = uuid_addr[2];
248 ((unsigned char*)pUuid->Data4)[5] = uuid_addr[3];
249 ((unsigned char*)pUuid->Data4)[6] = uuid_addr[4];
250 ((unsigned char*)pUuid->Data4)[7] = uuid_addr[5];
251
252 return S_OK;
253}
254
255// ----------------------------------------------------------------------
256// UuidCreateNil
257// ----------------------------------------------------------------------
258RPCRTAPI
259RPC_STATUS
260RPC_ENTRY
261UuidCreateNil (
262 OUT UUID __RPC_FAR * NilUuid
263 )
264{
265 dprintf(("RPCRT4: %s", __FUNCTION__));
266
267 memset (NilUuid, 0, sizeof (uuid_t));
268
269 return RPC_S_OK;
270}
271
272
273// ----------------------------------------------------------------------
274// UuidToStringA
275// Memory allocated here should be released via RpcStringFreeA
276// ----------------------------------------------------------------------
277RPCRTAPI
278RPC_STATUS
279RPC_ENTRY
280UuidToStringA (
281 IN UUID __RPC_FAR * Uuid,
282 OUT unsigned char __RPC_FAR * __RPC_FAR * StringUuid
283 )
284{
285 char * pString;
286
287 dprintf(("RPCRT4: %s", __FUNCTION__));
288
289 if ((pString = (char *)HeapAlloc(GetProcessHeap(), 0, 40)) == NULL)
290 return RPC_S_OUT_OF_MEMORY;
291
292 // Setup new string...
293 sprintf(pString, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
294 Uuid->Data1,
295 Uuid->Data2,
296 Uuid->Data3,
297 Uuid->Data4[0],
298 Uuid->Data4[1],
299 Uuid->Data4[2],
300 Uuid->Data4[3],
301 Uuid->Data4[4],
302 Uuid->Data4[5],
303 Uuid->Data4[6],
304 Uuid->Data4[7]);
305
306 *StringUuid = (unsigned char *)pString;
307
308 return RPC_S_OK;
309}
310
311
312// ----------------------------------------------------------------------
313// UuidFromStringA
314// ----------------------------------------------------------------------
315RPCRTAPI
316RPC_STATUS
317RPC_ENTRY
318UuidFromStringA (
319 IN unsigned char __RPC_FAR * StringUuid,
320 OUT UUID __RPC_FAR * Uuid
321 )
322{
323 dprintf(("RPCRT4: %s", __FUNCTION__));
324
325 // Convert to binary CLSID
326 char *s = (char *) StringUuid;
327 char *p;
328 int i;
329 char table[256];
330
331 /* quick lookup table */
332 memset(table, 0, 256);
333
334 for (i = 0; i < 10; i++)
335 {
336 table['0' + i] = i;
337 }
338 for (i = 0; i < 6; i++)
339 {
340 table['A' + i] = i+10;
341 table['a' + i] = i+10;
342 }
343
344 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
345
346 if (lstrlenA(s) != 38)
347 return RPC_S_INVALID_STRING_UUID;
348
349 p = (char *) Uuid;
350
351 s++; /* skip leading brace */
352 for (i = 0; i < 4; i++)
353 {
354 p[3 - i] = table[*s]<<4 | table[*(s+1)];
355 s += 2;
356 }
357 p += 4;
358 s++; /* skip - */
359
360 for (i = 0; i < 2; i++)
361 {
362 p[1-i] = table[*s]<<4 | table[*(s+1)];
363 s += 2;
364 }
365 p += 2;
366 s++; /* skip - */
367
368 for (i = 0; i < 2; i++)
369 {
370 p[1-i] = table[*s]<<4 | table[*(s+1)];
371 s += 2;
372 }
373 p += 2;
374 s++; /* skip - */
375
376 /* these are just sequential bytes */
377 for (i = 0; i < 2; i++)
378 {
379 *p++ = table[*s]<<4 | table[*(s+1)];
380 s += 2;
381 }
382 s++; /* skip - */
383
384 for (i = 0; i < 6; i++)
385 {
386 *p++ = table[*s]<<4 | table[*(s+1)];
387 s += 2;
388 }
389
390 return RPC_S_OK;
391}
392
393
394// ----------------------------------------------------------------------
395// UuidToStringW
396// Memory allocated here should be released via RpcStringFreeW
397// ----------------------------------------------------------------------
398RPCRTAPI
399RPC_STATUS
400RPC_ENTRY
401UuidToStringW (
402 IN UUID __RPC_FAR * Uuid,
403 OUT unsigned short __RPC_FAR * __RPC_FAR * StringUuid
404 )
405{
406 RPC_STATUS rc;
407 unsigned char * pStringA;
408 WCHAR * pStringW;
409 size_t strLen;
410
411 dprintf(("RPCRT4: %s", __FUNCTION__));
412
413 // jic
414 *StringUuid = 0;
415
416 // Setup new string...
417 if ((rc = UuidToStringA(Uuid, &pStringA)) != RPC_S_OK)
418 return rc; // Boom...
419
420 strLen = strlen((char *)pStringA);
421
422 // Grab buffer for string...
423 if ((pStringW = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, (strLen + 1) * sizeof(WCHAR))) == NULL)
424 rc = RPC_S_OUT_OF_MEMORY;
425 else
426 {
427 AsciiToUnicode((char *)pStringA, pStringW);
428 *StringUuid = (LPOLESTR)pStringW;
429 rc = RPC_S_OK;
430 }
431
432 // Free the ASCII string
433 RpcStringFreeA(&pStringA);
434
435 return rc;
436}
437
438
439// ----------------------------------------------------------------------
440// UuidFromStringW
441// ----------------------------------------------------------------------
442RPCRTAPI
443RPC_STATUS
444RPC_ENTRY
445UuidFromStringW (
446 IN unsigned short __RPC_FAR * StringUuid,
447 OUT UUID __RPC_FAR * Uuid
448 )
449{
450 unsigned char tmp[40];
451
452 dprintf(("RPCRT4: %s", __FUNCTION__));
453
454 UnicodeToAscii((LPWSTR)StringUuid, (char *)tmp);
455 return UuidFromStringA(tmp, Uuid);
456}
457
458
459// ----------------------------------------------------------------------
460// UuidCompare
461// ----------------------------------------------------------------------
462RPCRTAPI
463signed int
464RPC_ENTRY
465UuidCompare (
466 IN UUID __RPC_FAR * Uuid1,
467 IN UUID __RPC_FAR * Uuid2,
468 OUT RPC_STATUS __RPC_FAR * Status
469 )
470{
471 int ii;
472
473 dprintf(("RPCRT4: %s", __FUNCTION__));
474
475 /*
476 * check to see if either of the arguments is a NULL pointer
477 * - if so, compare the other argument to the nil Uuid
478 */
479 if (Uuid1 == NULL)
480 {
481 /*
482 * if both arguments are NULL, so is this routine
483 */
484 if (Uuid2 == NULL)
485 {
486 *Status = RPC_S_OK;
487 return (0);
488 }
489
490 return (UuidIsNil (Uuid2, Status) ? 0 : -1);
491 }
492
493 if (Uuid2 == NULL)
494 {
495 return (UuidIsNil (Uuid1, Status) ? 0 : 1);
496 }
497 *Status = RPC_S_OK;
498
499 if (Uuid1->Data1 == Uuid2->Data1)
500 {
501 if (Uuid1->Data2 == Uuid2->Data2)
502 {
503 if (Uuid1->Data3 == Uuid2->Data3)
504 {
505 if (Uuid1->Data4[0] == Uuid2->Data4[0])
506 {
507 if (Uuid1->Data4[1] == Uuid2->Data4[1])
508 {
509 for (ii = 2; ii < 8; ii++)
510 {
511 if (Uuid1->Data4[ii] < Uuid2->Data4[ii])
512 return (-1);
513 if (Uuid1->Data4[ii] > Uuid2->Data4[ii])
514 return (1);
515 }
516 return (0);
517 } /* end if - clock_seq_low */
518 else
519 {
520 if (Uuid1->Data4[1] < Uuid2->Data4[1])
521 return (-1);
522 else
523 return (1);
524 } /* end else - clock_seq_low */
525 } /* end if - clock_seq_hi_and_reserved */
526 else
527 {
528 if (Uuid1->Data4[0] < Uuid2->Data4[0])
529 return (-1);
530 else
531 return (1);
532 } /* end else - clock_seq_hi_and_reserved */
533 } /* end if - time_hi_and_version */
534 else
535 {
536 if (Uuid1->Data3 < Uuid2->Data3)
537 return (-1);
538 else
539 return (1);
540 } /* end else - time_hi_and_version */
541 } /* end if - time_mid */
542 else
543 {
544 if (Uuid1->Data2 < Uuid2->Data2)
545 return (-1);
546 else
547 return (1);
548 } /* end else - time_mid */
549 } /* end if - time_low */
550 else
551 {
552 if (Uuid1->Data1 < Uuid2->Data1)
553 return (-1);
554 else
555 return (1);
556 } /* end else - time_low */
557}
558
559
560// ----------------------------------------------------------------------
561// UuidEqual
562// ----------------------------------------------------------------------
563RPCRTAPI
564int
565RPC_ENTRY
566UuidEqual (
567 IN UUID __RPC_FAR * Uuid1,
568 IN UUID __RPC_FAR * Uuid2,
569 OUT RPC_STATUS __RPC_FAR * Status
570 )
571{
572 dprintf(("RPCRT4: %s", __FUNCTION__));
573 *Status = RPC_S_OK;
574 return IsEqualGUID(Uuid1, Uuid2);
575}
576
577
578// ----------------------------------------------------------------------
579// UuidHash
580// ----------------------------------------------------------------------
581RPCRTAPI
582unsigned short
583RPC_ENTRY
584UuidHash (
585 IN UUID __RPC_FAR * Uuid,
586 OUT RPC_STATUS __RPC_FAR * Status
587 )
588{
589 dprintf(("RPCRT4: %s", __FUNCTION__));
590
591 short c0, c1;
592 short x, y;
593 char * next_uuid;
594
595 /*
596 * initialize counters
597 */
598 c0 = c1 = 0;
599 next_uuid = (char *) Uuid;
600
601 /*
602 * For speed lets unroll the following loop:
603 *
604 * for (i = 0; i < UUID_K_LENGTH; i++)
605 * {
606 * c0 = c0 + *next_uuid++;
607 * c1 = c1 + c0;
608 * }
609 */
610 c0 = c0 + *next_uuid++;
611 c1 = c1 + c0;
612 c0 = c0 + *next_uuid++;
613 c1 = c1 + c0;
614 c0 = c0 + *next_uuid++;
615 c1 = c1 + c0;
616 c0 = c0 + *next_uuid++;
617 c1 = c1 + c0;
618
619 c0 = c0 + *next_uuid++;
620 c1 = c1 + c0;
621 c0 = c0 + *next_uuid++;
622 c1 = c1 + c0;
623 c0 = c0 + *next_uuid++;
624 c1 = c1 + c0;
625 c0 = c0 + *next_uuid++;
626 c1 = c1 + c0;
627
628 c0 = c0 + *next_uuid++;
629 c1 = c1 + c0;
630 c0 = c0 + *next_uuid++;
631 c1 = c1 + c0;
632 c0 = c0 + *next_uuid++;
633 c1 = c1 + c0;
634 c0 = c0 + *next_uuid++;
635 c1 = c1 + c0;
636
637 c0 = c0 + *next_uuid++;
638 c1 = c1 + c0;
639 c0 = c0 + *next_uuid++;
640 c1 = c1 + c0;
641 c0 = c0 + *next_uuid++;
642 c1 = c1 + c0;
643 c0 = c0 + *next_uuid++;
644 c1 = c1 + c0;
645
646 /*
647 * Calculate the value for "First octet" of the hash
648 */
649 x = -c1 % 255;
650 if (x < 0)
651 {
652 x = x + 255;
653 }
654
655 /*
656 * Calculate the value for "second octet" of the hash
657 */
658 y = (c1 - c0) % 255;
659 if (y < 0)
660 {
661 y = y + 255;
662 }
663
664 /*
665 * return the pieces put together
666 */
667 *Status = RPC_S_OK;
668
669 return ((y * 256) + x);
670}
671
672
673// ----------------------------------------------------------------------
674// UuidIsNil
675// ----------------------------------------------------------------------
676RPCRTAPI
677int
678RPC_ENTRY
679UuidIsNil (
680 IN UUID __RPC_FAR * Uuid,
681 OUT RPC_STATUS __RPC_FAR * Status
682 )
683{
684 dprintf(("RPCRT4: %s", __FUNCTION__));
685 return IsEqualGUID(Uuid, &uuid_nil);
686}
687
Note: See TracBrowser for help on using the repository browser.