source: trunk/src/rpcrt4/uuid.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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