2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
30 #if defined(__WIN32__)
31 /* _CFGenerateUUID function just calls the COM library's UUID generator
32 * (Aleksey Dukhnyakov)
38 unsigned long _CFGenerateUUID(uuid_t
*uuid
) {
41 /* call GetScode() function to get RPC_STATUS, because
42 * CoCreateGuid(uuid) function return HRESULT type
44 rStatus
= GetScode(CoCreateGuid(uuid
));
46 /* We accept only following results RPC_S_OK, RPC_S_UUID_LOCAL_ONLY
48 if ( rStatus
== RPC_S_UUID_NO_ADDRESS
)
58 * Modifications made by William Woody to make this thing
59 * work on the Macintosh.
64 * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC.
65 * (c) Copyright 1989 HEWLETT-PACKARD COMPANY
66 * (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION
67 * To anyone who acknowledges that this file is provided "AS IS"
68 * without any express or implied warranty:
69 * permission to use, copy, modify, and distribute this
70 * file for any purpose is hereby granted without fee, provided that
71 * the above copyright notices and this notice appears in all source
72 * code copies, and that none of the names of Open Software
73 * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment
74 * Corporation be used in advertising or publicity pertaining to
75 * distribution of the software without specific, written prior
76 * permission. Neither Open Software Foundation, Inc., Hewlett-
77 * Packard Company, nor Digital Equipment Corporation makes any
78 * representations about the suitability of this software for any
96 ** UUID - routines that manipulate uuid's
101 #include <CoreFoundation/CFBase.h>
102 #include <CoreFoundation/CFDate.h>
103 #include "CFInternal.h"
107 /* uuid_t already defined in RPCDCE.H (WIN32 header)
108 * (Aleksey Dukhnyakov)
110 #if defined(__WIN32__)
111 #define UUID_T_DEFINED 1
114 #if !defined(UUID_T_DEFINED)
115 #define UUID_T_DEFINED 1
119 * Universal Unique ID. Note this definition will result is a 16-byte
120 * structure regardless what platform it is on.
124 unsigned long time_low
;
125 unsigned short time_mid
;
126 unsigned short time_hi_and_version
;
127 unsigned char clock_seq_hi_and_reserved
;
128 unsigned char clock_seq_low
;
129 unsigned char node
[6];
132 typedef struct uuid_t uuid_t
;
137 kUUIDInternalError
= -21001,
138 kUUIDInvalidString
= -21002
141 extern unsigned long _CFGenerateUUID(uuid_t
*uuid
);
145 unsigned char eaddr
[6]; /* 6 bytes of ethernet hardware address */
153 static OSErr
GenRandomEthernet(uuid_address_t
*addr
);
154 static OSErr
GetEthernetAddr(uuid_address_t
*addr
);
156 static OSErr
ReadPrefData(void);
159 * Preferences file management
162 static uuid_address_t GSavedENetAddr
= {{0, 0, 0, 0, 0, 0}};
163 static uuid_time_t GLastTime
= {0, 0}; /* Clock state info */
164 static unsigned short GTimeAdjust
= 0;
165 static unsigned short GClockSeq
= 0;
169 * Internal structure of universal unique IDs (UUIDs).
171 * There are three "variants" of UUIDs that this code knows about. The
172 * variant #0 is what was defined in the 1989 HP/Apollo Network Computing
173 * Architecture (NCA) specification and implemented in NCS 1.x and DECrpc
174 * v1. Variant #1 is what was defined for the joint HP/DEC specification
175 * for the OSF (in DEC's "UID Architecture Functional Specification Version
176 * X1.0.4") and implemented in NCS 2.0, DECrpc v2, and OSF 1.0 DCE RPC.
177 * Variant #2 is defined by Microsoft.
179 * This code creates only variant #1 UUIDs.
181 * The three UUID variants can exist on the same wire because they have
182 * distinct values in the 3 MSB bits of octet 8 (see table below). Do
183 * NOT confuse the version number with these 3 bits. (Note the distinct
184 * use of the terms "version" and "variant".) Variant #0 had no version
185 * field in it. Changes to variant #1 (should any ever need to be made)
186 * can be accomodated using the current form's 4 bit version field.
188 * The UUID record structure MUST NOT contain padding between fields.
189 * The total size = 128 bits.
191 * To minimize confusion about bit assignment within octets, the UUID
192 * record definition is defined only in terms of fields that are integral
195 * Depending on the network data representation, the multi-octet unsigned
196 * integer fields are subject to byte swapping when communicated between
197 * dissimilar endian machines. Note that all three UUID variants have
198 * the same record structure; this allows this byte swapping to occur.
199 * (The ways in which the contents of the fields are generated can and
202 * The following information applies to variant #1 UUIDs:
204 * The lowest addressed octet contains the global/local bit and the
205 * unicast/multicast bit, and is the first octet of the address transmitted
208 * The adjusted time stamp is split into three fields, and the clockSeq
209 * is split into two fields.
211 * |<------------------------- 32 bits -------------------------->|
213 * +--------------------------------------------------------------+
214 * | low 32 bits of time | 0-3 .time_low
215 * +-------------------------------+-------------------------------
216 * | mid 16 bits of time | 4-5 .time_mid
217 * +-------+-----------------------+
218 * | vers. | hi 12 bits of time | 6-7 .time_hi_and_version
219 * +-------+-------+---------------+
220 * |Res| clkSeqHi | 8 .clock_seq_hi_and_reserved
222 * | clkSeqLow | 9 .clock_seq_low
223 * +---------------+----------...-----+
224 * | node ID | 8-16 .node
225 * +--------------------------...-----+
227 * --------------------------------------------------------------------------
229 * The structure layout of all three UUID variants is fixed for all time.
230 * I.e., the layout consists of a 32 bit int, 2 16 bit ints, and 8 8
231 * bit ints. The current form version field does NOT determine/affect
232 * the layout. This enables us to do certain operations safely on the
233 * variants of UUIDs without regard to variant; this increases the utility
234 * of this code even as the version number changes (i.e., this code does
235 * NOT need to check the version field).
237 * The "Res" field in the octet #8 is the so-called "reserved" bit-field
238 * and determines whether or not the uuid is a old, current or other
241 * MS-bit 2MS-bit 3MS-bit Variant
242 * ---------------------------------------------
244 * 1 0 x 1 (DCE 1.0 RPC)
245 * 1 1 0 2 (Microsoft)
248 * --------------------------------------------------------------------------
250 * Internal structure of variant #0 UUIDs
252 * The first 6 octets are the number of 4 usec units of time that have
253 * passed since 1/1/80 0000 GMT. The next 2 octets are reserved for
254 * future use. The next octet is an address family. The next 7 octets
255 * are a host ID in the form allowed by the specified address family.
257 * Note that while the family field (octet 8) was originally conceived
258 * of as being able to hold values in the range [0..255], only [0..13]
259 * were ever used. Thus, the 2 MSB of this field are always 0 and are
260 * used to distinguish old and current UUID forms.
262 * +--------------------------------------------------------------+
263 * | high 32 bits of time | 0-3 .time_high
264 * +-------------------------------+-------------------------------
265 * | low 16 bits of time | 4-5 .time_low
266 * +-------+-----------------------+
267 * | reserved | 6-7 .reserved
268 * +---------------+---------------+
269 * | family | 8 .family
270 * +---------------+----------...-----+
271 * | node ID | 9-16 .node
272 * +--------------------------...-----+
276 /***************************************************************************
280 **************************************************************************/
282 static const long uuid_c_version
= 1;
285 * local defines used in uuid bit-diddling
287 #define HI_WORD(w) ((w) >> 16)
288 #define RAND_MASK 0x3fff /* same as CLOCK_SEQ_LAST */
290 #define TIME_MID_MASK 0x0000ffff
291 #define TIME_HIGH_MASK 0x0fff0000
292 #define TIME_HIGH_SHIFT_COUNT 16
295 * The following was modified in order to prevent overlap because
296 * our clock is (theoretically) accurate to 1us (or 1s in CarbonLib)
300 #define MAX_TIME_ADJUST 9 /* Max adjust before tick */
302 #define CLOCK_SEQ_LOW_MASK 0xff
303 #define CLOCK_SEQ_HIGH_MASK 0x3f00
304 #define CLOCK_SEQ_HIGH_SHIFT_COUNT 8
305 #define CLOCK_SEQ_FIRST 1
306 #define CLOCK_SEQ_LAST 0x3fff /* same as RAND_MASK */
309 * Note: If CLOCK_SEQ_BIT_BANG == true, then we can avoid the modulo
310 * operation. This should save us a divide instruction and speed
314 #ifndef CLOCK_SEQ_BIT_BANG
315 #define CLOCK_SEQ_BIT_BANG 1
318 #if CLOCK_SEQ_BIT_BANG
319 #define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) & CLOCK_SEQ_LAST)
321 #define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) % (CLOCK_SEQ_LAST+1))
324 #define UUID_VERSION_BITS (uuid_c_version << 12)
325 #define UUID_RESERVED_BITS 0x80
327 #define IS_OLD_UUID(uuid) (((uuid)->clock_seq_hi_and_reserved & 0xc0) != 0x80)
329 /****************************************************************************
331 * local data declarations
333 ****************************************************************************/
341 * declarations used in UTC time calculations
344 static uuid_time_t time_now
= {0, 0}; /* utc time as of last query */
345 //static uuid_time_t time_last; /* utc time last time I looked */
346 //static unsigned short time_adjust; /* 'adjustment' to ensure uniqness */
347 //static unsigned short clock_seq; /* 'adjustment' for backwards clocks*/
350 * true_random variables
353 static unsigned long rand_m
= 0; /* multiplier */
354 static unsigned long rand_ia
= 0; /* adder #1 */
355 static unsigned long rand_ib
= 0; /* adder #2 */
356 static unsigned long rand_irand
= 0; /* random value */
360 uuid_e_less_than
, uuid_e_equal_to
, uuid_e_greater_than
366 /****************************************************************************
368 * local function declarations
370 ****************************************************************************/
375 * Startup initialization routine for UUID module.
378 static OSErr
init (void);
381 * T R U E _ R A N D O M _ I N I T
384 static void true_random_init (void);
387 * T R U E _ R A N D O M
389 static unsigned short true_random (void);
393 * N E W _ C L O C K _ S E Q
395 * Ensure clock_seq is up-to-date
397 * Note: clock_seq is architected to be 14-bits (unsigned) but
398 * I've put it in here as 16-bits since there isn't a
399 * 14-bit unsigned integer type (yet)
401 static void new_clock_seq ( unsigned short * /*clock_seq*/);
407 * Compares two UUID times (64-bit DEC UID UTC values)
409 static uuid_compval_t
time_cmp (
410 uuid_time_t
* /*time1*/,
411 uuid_time_t
* /*time2*/
415 /************************************************************************/
419 /************************************************************************/
422 * saved copy of our IEEE 802 address for quick reference
425 static uuid_address_t saved_addr
= {{0, 0, 0, 0, 0, 0}};
426 static int got_address
= false;
427 static int last_addr_result
= false;
433 ** ROUTINE NAME: uuid_get_address
439 ** Return our IEEE 802 address.
441 ** This function is not really "public", but more like the SPI functions
442 ** -- available but not part of the official API. We've done this so
443 ** that other subsystems (of which there are hopefully few or none)
444 ** that need the IEEE 802 address can use this function rather than
445 ** duplicating the gore it does (or more specifically, the gore that
446 ** "uuid__get_os_address" does).
450 ** INPUTS/OUTPUTS: none
454 ** addr IEEE 802 address
456 ** status return status value
458 ** IMPLICIT INPUTS: none
460 ** IMPLICIT OUTPUTS: none
462 ** FUNCTION VALUE: none
464 ** SIDE EFFECTS: none
469 static int uuid_get_address(uuid_address_t
*addr
)
473 * just return address we determined previously if we've
478 memmove (addr
, &saved_addr
, sizeof (uuid_address_t
));
479 return last_addr_result
;
483 * Otherwise, call the system specific routine.
486 last_addr_result
= GetEthernetAddr(addr
);
489 * Was this an error? If so, I need to generate a random
490 * sequence to use in place of an Ethernet address.
492 if (last_addr_result
) {
493 last_addr_result
= GenRandomEthernet(addr
);
497 if (last_addr_result
== 0) {
498 /* On no error copy */
499 memmove (&saved_addr
, addr
, sizeof (uuid_address_t
));
501 return last_addr_result
;
504 static OSErr
GenRandomEthernet(uuid_address_t
*addr
) {
506 for (i
= 0; i
< 6; i
++) {
507 addr
->eaddr
[i
] = (unsigned char)(true_random() & 0xff);
512 __private_extern__ CFStringRef
__CFCopyRegularEthernetAddrString(void) {
514 static CFStringRef string
= NULL
;
515 static Boolean lookedUpAddr
= false;
518 // dont use the cache, since a random enet addr might have been put in it
519 if (GetEthernetAddr(&addr
) == 0) {
520 string
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), addr
.eaddr
[0], addr
.eaddr
[1], addr
.eaddr
[2], addr
.eaddr
[3], addr
.eaddr
[4], addr
.eaddr
[5]);
524 return (string
? CFRetain(string
) : NULL
);
527 __private_extern__ CFStringRef
__CFCopyEthernetAddrString(void) {
529 static CFStringRef string
= NULL
;
530 static Boolean lookedUpAddr
= false;
533 // dont use the cache, since a random enet addr might have been put in it
534 if (GetEthernetAddr(&addr
) == 0) {
535 string
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%02x%02x%02x%02x%02x%02x"), addr
.eaddr
[0], addr
.eaddr
[1], addr
.eaddr
[2], addr
.eaddr
[3], addr
.eaddr
[4], addr
.eaddr
[5]);
539 return (string
? CFRetain(string
) : NULL
);
542 /*****************************************************************************
546 ****************************************************************************/
549 * ensure we've been initialized
551 static int uuid_init_done
= false;
554 #define UUID_VERIFY_INIT(Arg) \
555 if (! uuid_init_done) \
558 if (*status != uuid_s_ok) \
565 * Check the reserved bits to make sure the UUID is of the known structure.
568 #define CHECK_STRUCTURE(uuid) \
570 (((uuid)->clock_seq_hi_and_reserved & 0x80) == 0x00) || /* var #0 */ \
571 (((uuid)->clock_seq_hi_and_reserved & 0xc0) == 0x80) || /* var #1 */ \
572 (((uuid)->clock_seq_hi_and_reserved & 0xe0) == 0xc0) /* var #2 */ \
576 * The following macros invoke CHECK_STRUCTURE(), check that the return
577 * value is okay and if not, they set the status variable appropriately
578 * and return either a boolean false, nothing (for void procedures),
579 * or a value passed to the macro. This has been done so that checking
580 * can be done more simply and values are returned where appropriate
581 * to keep compilers happy.
583 * bCHECK_STRUCTURE - returns boolean false
584 * vCHECK_STRUCTURE - returns nothing (void)
585 * rCHECK_STRUCTURE - returns 'r' macro parameter
588 #define bCHECK_STRUCTURE(uuid, status) \
590 if (!CHECK_STRUCTURE (uuid)) \
592 *(status) = uuid_s_bad_version; \
597 #define vCHECK_STRUCTURE(uuid, status) \
599 if (!CHECK_STRUCTURE (uuid)) \
601 *(status) = uuid_s_bad_version; \
606 #define rCHECK_STRUCTURE(uuid, status, result) \
608 if (!CHECK_STRUCTURE (uuid)) \
610 *(status) = uuid_s_bad_version; \
617 * Define constant designation difference in Unix and DTSS base times:
618 * DTSS UTC base time is October 15, 1582.
619 * Unix base time is January 1, 1970.
621 #define uuid_c_os_base_time_diff_lo 0x13814000
622 #define uuid_c_os_base_time_diff_hi 0x01B21DD2
624 #ifndef UUID_C_100NS_PER_SEC
625 #define UUID_C_100NS_PER_SEC 10000000
628 #ifndef UUID_C_100NS_PER_USEC
629 #define UUID_C_100NS_PER_USEC 10
637 * UADD_UVLW_2_UVLW - macro to add two unsigned 64-bit long integers
638 * (ie. add two unsigned 'very' long words)
640 * Important note: It is important that this macro accommodate (and it does)
641 * invocations where one of the addends is also the sum.
643 * This macro was snarfed from the DTSS group and was originally:
645 * UTCadd - macro to add two UTC times
647 * add lo and high order longword separately, using sign bits of the low-order
648 * longwords to determine carry. sign bits are tested before addition in two
649 * cases - where sign bits match. when the addend sign bits differ the sign of
650 * the result is also tested:
653 * addend 1 addend 2 carry?
656 * 1 0 true if sign of sum clear
657 * 0 1 true if sign of sum clear
660 #define UADD_UVLW_2_UVLW(add1, add2, sum) \
661 if (!(((add1)->lo&0x80000000UL) ^ ((add2)->lo&0x80000000UL))) \
663 if (((add1)->lo&0x80000000UL)) \
665 (sum)->lo = (add1)->lo + (add2)->lo ; \
666 (sum)->hi = (add1)->hi + (add2)->hi+1 ; \
670 (sum)->lo = (add1)->lo + (add2)->lo ; \
671 (sum)->hi = (add1)->hi + (add2)->hi ; \
676 (sum)->lo = (add1)->lo + (add2)->lo ; \
677 (sum)->hi = (add1)->hi + (add2)->hi ; \
678 if (!((sum)->lo&0x80000000UL)) \
683 * UADD_UW_2_UVLW - macro to add a 16-bit unsigned integer to
684 * a 64-bit unsigned integer
686 * Note: see the UADD_UVLW_2_UVLW() macro
689 #define UADD_UW_2_UVLW(add1, add2, sum) \
691 (sum)->hi = (add2)->hi; \
692 if ((add2)->lo & 0x80000000UL) \
694 (sum)->lo = (*add1) + (add2)->lo; \
695 if (!((sum)->lo & 0x80000000UL)) \
702 (sum)->lo = (*add1) + (add2)->lo; \
707 * U U I D _ _ G E T _ O S _ T I M E
709 * Get OS time - contains platform-specific code.
712 static const double utc_conversion_factor
= 429.4967296; // 2^32 / 10^7
714 static void uuid__get_os_time (uuid_time_t
* uuid_time
)
718 CFAbsoluteTime at
= CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970
;
719 double utc_at
= at
/ utc_conversion_factor
;
721 /* Convert 'at' in double seconds to 100ns units in utc */
722 utc
.hi
= (unsigned long)utc_at
;
723 utc_at
-= (double)utc
.hi
;
724 utc_at
*= utc_conversion_factor
;
725 utc_at
*= 10000000.0;
726 utc
.lo
= (unsigned long)utc_at
;
729 * Offset between DTSS formatted times and Unix formatted times.
731 os_basetime_diff
.lo
= uuid_c_os_base_time_diff_lo
;
732 os_basetime_diff
.hi
= uuid_c_os_base_time_diff_hi
;
733 UADD_UVLW_2_UVLW (&utc
, &os_basetime_diff
, uuid_time
);
740 ** ROUTINE NAME: init
742 ** SCOPE: INTERNAL - declared locally
746 ** Startup initialization routine for the UUID module.
750 ** INPUTS/OUTPUTS: none
754 ** status return status value
757 ** uuid_s_coding_error
759 ** IMPLICIT INPUTS: none
761 ** IMPLICIT OUTPUTS: none
763 ** FUNCTION VALUE: void
765 ** SIDE EFFECTS: sets uuid_init_done so this won't be done again
773 * init the random number generator
779 * Read the preferences data from the Macintosh pref file
785 * Get the time. Note that I renamed 'time_last' to
786 * GLastTime to indicate that I'm using it elsewhere as
787 * a shared library global.
790 if ((GLastTime
.hi
== 0) && (GLastTime
.lo
== 0)) {
791 uuid__get_os_time (&GLastTime
);
792 GClockSeq
= true_random();
794 uuid_init_done
= true;
799 ** New name: GenerateUID
803 ** ROUTINE NAME: uuid_create
805 ** SCOPE: PUBLIC - declared in UUID.IDL
809 ** Create a new UUID. Note: we only know how to create the new
810 ** and improved UUIDs.
814 ** INPUTS/OUTPUTS: none
818 ** uuid A new UUID value
820 ** status return status value
823 ** uuid_s_coding_error
825 ** IMPLICIT INPUTS: none
827 ** IMPLICIT OUTPUTS: none
829 ** FUNCTION VALUE: void
831 ** SIDE EFFECTS: none
837 PUBLIC void uuid_create
841 unsigned long *status
846 unsigned long *status;
850 __private_extern__
unsigned long _CFGenerateUUID(uuid_t
*uuid
)
853 uuid_address_t eaddr
;
854 int got_no_time
= false;
856 if (!uuid_init_done
) {
861 * get our hardware network address
864 if (0 != (err
= uuid_get_address(&eaddr
))) return err
;
869 * get the current time
871 uuid__get_os_time (&time_now
);
876 * o check that our clock hasn't gone backwards and handle it
877 * accordingly with clock_seq
878 * o check that we're not generating uuid's faster than we
879 * can accommodate with our time_adjust fudge factor
881 switch (time_cmp (&time_now
, &GLastTime
))
883 case uuid_e_less_than
:
884 new_clock_seq (&GClockSeq
);
887 case uuid_e_greater_than
:
890 case uuid_e_equal_to
:
891 if (GTimeAdjust
== MAX_TIME_ADJUST
)
894 * spin your wheels while we wait for the clock to tick
904 return kUUIDInternalError
;
906 } while (got_no_time
);
908 GLastTime
.lo
= time_now
.lo
;
909 GLastTime
.hi
= time_now
.hi
;
911 if (GTimeAdjust
!= 0)
913 UADD_UW_2_UVLW (>imeAdjust
, &time_now
, &time_now
);
917 * now construct a uuid with the information we've gathered
918 * plus a few constants
920 uuid
->time_low
= time_now
.lo
;
921 uuid
->time_mid
= time_now
.hi
& TIME_MID_MASK
;
923 uuid
->time_hi_and_version
=
924 (time_now
.hi
& TIME_HIGH_MASK
) >> TIME_HIGH_SHIFT_COUNT
;
925 uuid
->time_hi_and_version
|= UUID_VERSION_BITS
;
927 uuid
->clock_seq_low
= GClockSeq
& CLOCK_SEQ_LOW_MASK
;
928 uuid
->clock_seq_hi_and_reserved
=
929 (GClockSeq
& CLOCK_SEQ_HIGH_MASK
) >> CLOCK_SEQ_HIGH_SHIFT_COUNT
;
931 uuid
->clock_seq_hi_and_reserved
|= UUID_RESERVED_BITS
;
933 memmove (uuid
->node
, &eaddr
, sizeof (uuid_address_t
));
938 /*****************************************************************************
940 * LOCAL MATH PROCEDURES - math procedures used internally by the UUID module
942 ****************************************************************************/
947 ** Compares two UUID times (64-bit UTC values)
950 static uuid_compval_t
time_cmp(uuid_time_t
*time1
,uuid_time_t
*time2
)
953 * first check the hi parts
955 if (time1
->hi
< time2
->hi
) return (uuid_e_less_than
);
956 if (time1
->hi
> time2
->hi
) return (uuid_e_greater_than
);
959 * hi parts are equal, check the lo parts
961 if (time1
->lo
< time2
->lo
) return (uuid_e_less_than
);
962 if (time1
->lo
> time2
->lo
) return (uuid_e_greater_than
);
964 return (uuid_e_equal_to
);
969 /****************************************************************************
971 ** U U I D T R U E R A N D O M N U M B E R G E N E R A T O R
973 *****************************************************************************
975 ** This random number generator (RNG) was found in the ALGORITHMS Notesfile.
977 ** (Note 16.7, July 7, 1989 by Robert (RDVAX::)Gries, Cambridge Research Lab,
978 ** Computational Quality Group)
980 ** It is really a "Multiple Prime Random Number Generator" (MPRNG) and is
981 ** completely discussed in reference #1 (see below).
984 ** 1) "The Multiple Prime Random Number Generator" by Alexander Hass
985 ** pp. 368 to 381 in ACM Transactions on Mathematical Software,
987 ** 2) "The Art of Computer Programming: Seminumerical Algorithms
988 ** (vol 2)" by Donald E. Knuth, pp. 39 to 113.
990 ** A summary of the notesfile entry follows:
992 ** Gries discusses the two RNG's available for ULTRIX-C. The default RNG
993 ** uses a Linear Congruential Method (very popular) and the second RNG uses
994 ** a technique known as a linear feedback shift register.
996 ** The first (default) RNG suffers from bit-cycles (patterns/repetition),
997 ** ie. it's "not that random."
999 ** While the second RNG passes all the emperical tests, there are "states"
1000 ** that become "stable", albeit contrived.
1002 ** Gries then presents the MPRNG and says that it passes all emperical
1003 ** tests listed in reference #2. In addition, the number of calls to the
1004 ** MPRNG before a sequence of bit position repeats appears to have a normal
1007 ** Note (mbs): I have coded the Gries's MPRNG with the same constants that
1008 ** he used in his paper. I have no way of knowing whether they are "ideal"
1009 ** for the range of numbers we are dealing with.
1011 ****************************************************************************/
1014 ** T R U E _ R A N D O M _ I N I T
1016 ** Note: we "seed" the RNG with the bits from the clock and the PID
1020 static void true_random_init (void)
1023 unsigned short *seedp
, seed
=0;
1027 * optimal/recommended starting values according to the reference
1029 static unsigned long rand_m_init
= 971;
1030 static unsigned long rand_ia_init
= 11113;
1031 static unsigned long rand_ib_init
= 104322;
1032 static unsigned long rand_irand_init
= 4181;
1034 rand_m
= rand_m_init
;
1035 rand_ia
= rand_ia_init
;
1036 rand_ib
= rand_ib_init
;
1037 rand_irand
= rand_irand_init
;
1040 * Generating our 'seed' value
1042 * We start with the current time, but, since the resolution of clocks is
1043 * system hardware dependent (eg. Ultrix is 10 msec.) and most likely
1044 * coarser than our resolution (10 usec) we 'mixup' the bits by xor'ing
1045 * all the bits together. This will have the effect of involving all of
1046 * the bits in the determination of the seed value while remaining system
1047 * independent. Then for good measure to ensure a unique seed when there
1048 * are multiple processes creating UUID's on a system, we add in the PID.
1050 uuid__get_os_time(&t
);
1051 seedp
= (unsigned short *)(&t
);
1060 ** T R U E _ R A N D O M
1062 ** Note: we return a value which is 'tuned' to our purposes. Anyone
1063 ** using this routine should modify the return value accordingly.
1066 static unsigned short true_random (void)
1072 if (rand_m
>= 9973) rand_m
-= 9871;
1073 if (rand_ia
>= 99991) rand_ia
-= 89989;
1074 if (rand_ib
>= 224729) rand_ib
-= 96233;
1076 rand_irand
= (rand_irand
* rand_m
) + rand_ia
+ rand_ib
;
1078 return (HI_WORD (rand_irand
) ^ (rand_irand
& RAND_MASK
));
1081 /*****************************************************************************
1083 * LOCAL PROCEDURES - procedures used staticly by the UUID module
1085 ****************************************************************************/
1088 ** N E W _ C L O C K _ S E Q
1090 ** Ensure *clkseq is up-to-date
1092 ** Note: clock_seq is architected to be 14-bits (unsigned) but
1093 ** I've put it in here as 16-bits since there isn't a
1094 ** 14-bit unsigned integer type (yet)
1097 static void new_clock_seq
1100 unsigned short *clkseq
1104 unsigned short *clkseq
;
1108 * A clkseq value of 0 indicates that it hasn't been initialized.
1112 #ifdef UUID_NONVOLATILE_CLOCK
1113 *clkseq
= uuid__read_clock(); /* read nonvolatile clock */
1114 if (*clkseq
== 0) /* still not init'd ??? */
1116 *clkseq
= true_random(); /* yes, set random */
1120 * with a volatile clock, we always init to a random number
1122 *clkseq
= true_random();
1126 CLOCK_SEQ_BUMP (clkseq
);
1129 *clkseq
= *clkseq
+ 1;
1132 #ifdef UUID_NONVOLATILE_CLOCK
1133 uuid_write_clock (clkseq
);
1141 * Read the preferences data into my global variables
1144 static OSErr
ReadPrefData(void)
1147 * Zero out the saved preferences information
1150 memset((void *)&GSavedENetAddr
, 0, sizeof(GSavedENetAddr
));
1151 memset((void *)&GLastTime
, 0, sizeof(GLastTime
));
1163 * Write the preferences data back out to my global variables.
1164 * This gets called a couple of times. First, this is called by
1165 * my GetRandomEthernet routine if I generated a psudorandom MAC
1166 * address. Second, this is called when the library is being
1167 * terminated through the __terminate() CFM call.
1169 * Note this does it's best attempt at writing the data out,
1170 * and relies on ReadPrefData to check for integrety of the actual
1174 static void WritePrefData(void)
1181 #if defined(__MACH__)
1185 #include <sys/socket.h>
1186 #include <sys/ioctl.h>
1187 #include <sys/sockio.h>
1188 #include <sys/uio.h>
1189 #include <sys/errno.h>
1191 #include <netinet/in.h>
1193 #include <net/if_dl.h>
1194 #include <net/if_types.h>
1197 #define MAX(a, b) ((a) < (b) ? (b) : (a))
1200 #define IFR_NEXT(ifr) \
1201 ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \
1202 MAX(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr))))
1204 static OSErr
GetEthernetAddr(uuid_address_t
*addr
) {
1206 struct ifreq ifrbuf
[30], *ifr
;
1208 Boolean foundIt
= false;
1210 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
1214 ifc
.ifc_buf
= (caddr_t
)ifrbuf
;
1215 ifc
.ifc_len
= sizeof (ifrbuf
);
1216 if (ioctl(s
, SIOCGIFCONF
, &ifc
) == -1) {
1221 for (ifr
= (struct ifreq
*)ifc
.ifc_buf
, i
=0; (char *)ifr
< &ifc
.ifc_buf
[ifc
.ifc_len
]; ifr
= IFR_NEXT(ifr
), i
++) {
1222 unsigned char *p
, c
;
1224 if (*ifr
->ifr_name
== '\0') {
1228 * Adapt to buggy kernel implementation (> 9 of a type)
1231 p
= &ifr
->ifr_name
[strlen(ifr
->ifr_name
)-1];
1232 if ((c
= *p
) > '0'+9) {
1233 sprintf(p
, "%d", c
-'0');
1236 if (strcmp(ifr
->ifr_name
, "en0") == 0) {
1237 if (ifr
->ifr_addr
.sa_family
== AF_LINK
) {
1238 struct sockaddr_dl
*sa
= ((struct sockaddr_dl
*)&ifr
->ifr_addr
);
1239 if (sa
->sdl_type
== IFT_ETHER
|| sa
->sdl_type
== IFT_FDDI
|| sa
->sdl_type
== IFT_ISO88023
|| sa
->sdl_type
== IFT_ISO88024
|| sa
->sdl_type
== IFT_ISO88025
) {
1240 for (i
=0, p
=&sa
->sdl_data
[sa
->sdl_nlen
] ; i
++ < sa
->sdl_alen
; p
++) {
1241 addr
->eaddr
[i
-1] = *p
;
1250 return (foundIt
? 0 : -1);
1253 #elif defined (__WIN32__)
1255 #error Dont know how to find Ethernet Address on Win32
1256 // MF:!!! Maybe on Windows we should just call the COM library's UUID generator...
1258 #elif defined (__LINUX__) || defined(__FREEBSD__)
1260 static OSErr
GetEthernetAddr(uuid_address_t
*addr
) {
1268 #undef TIME_MID_MASK
1269 #undef TIME_HIGH_MASK
1270 #undef TIME_HIGH_SHIFT_COUNT
1271 #undef MAX_TIME_ADJUST
1272 #undef CLOCK_SEQ_LOW_MASK
1273 #undef CLOCK_SEQ_HIGH_MASK
1274 #undef CLOCK_SEQ_HIGH_SHIFT_COUNT
1275 #undef CLOCK_SEQ_FIRST
1276 #undef CLOCK_SEQ_LAST
1277 #undef CLOCK_SEQ_BIT_BANG
1278 #undef CLOCK_SEQ_BUMP
1279 #undef UUID_VERSION_BITS
1280 #undef UUID_RESERVED_BITS
1283 #undef UUID_VERIFY_INIT
1284 #undef CHECK_STRUCTURE
1285 #undef bCHECK_STRUCTURE
1286 #undef vCHECK_STRUCTURE
1287 #undef rCHECK_STRUCTURE
1288 #undef uuid_c_os_base_time_diff_lo
1289 #undef uuid_c_os_base_time_diff_hi
1290 #undef UUID_C_100NS_PER_SEC
1291 #undef UUID_C_100NS_PER_USEC
1292 #undef UADD_UVLW_2_UVLW
1293 #undef UADD_UW_2_UVLW