/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* uuid.c Copyright 1999-2002, Apple, Inc. All rights reserved. Responsibility: Doug Davidson */ #if defined(__WIN32__) /* _CFGenerateUUID function just calls the COM library's UUID generator * (Aleksey Dukhnyakov) */ #include <windows.h> #include <ole2.h> #include <objbase.h> unsigned long _CFGenerateUUID(uuid_t *uuid) { RPC_STATUS rStatus; /* call GetScode() function to get RPC_STATUS, because * CoCreateGuid(uuid) function return HRESULT type */ rStatus = GetScode(CoCreateGuid(uuid)); /* We accept only following results RPC_S_OK, RPC_S_UUID_LOCAL_ONLY */ if ( rStatus == RPC_S_UUID_NO_ADDRESS) return rStatus; return 0; }; #else /* uuid.c * * Modifications made by William Woody to make this thing * work on the Macintosh. */ /* * * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989 HEWLETT-PACKARD COMPANY * (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this * file for any purpose is hereby granted without fee, provided that * the above copyright notices and this notice appears in all source * code copies, and that none of the names of Open Software * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment * Corporation be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. Neither Open Software Foundation, Inc., Hewlett- * Packard Company, nor Digital Equipment Corporation makes any * representations about the suitability of this software for any * purpose. * */ /* */ /* ** ** NAME: ** ** uuid.c ** ** FACILITY: ** ** UUID ** ** ABSTRACT: ** ** UUID - routines that manipulate uuid's ** ** */ #include <CoreFoundation/CFBase.h> #include <CoreFoundation/CFDate.h> #include "CFInternal.h" #include <string.h> /* uuid_t already defined in RPCDCE.H (WIN32 header) * (Aleksey Dukhnyakov) */ #if defined(__WIN32__) #define UUID_T_DEFINED 1 #endif #if !defined(UUID_T_DEFINED) #define UUID_T_DEFINED 1 /* uuid * * Universal Unique ID. Note this definition will result is a 16-byte * structure regardless what platform it is on. */ struct uuid_t { unsigned long time_low; unsigned short time_mid; unsigned short time_hi_and_version; unsigned char clock_seq_hi_and_reserved; unsigned char clock_seq_low; unsigned char node[6]; }; typedef struct uuid_t uuid_t; #endif enum { kUUIDInternalError = -21001, kUUIDInvalidString = -21002 }; extern unsigned long _CFGenerateUUID(uuid_t *uuid); typedef struct { unsigned char eaddr[6]; /* 6 bytes of ethernet hardware address */ } uuid_address_t; typedef struct { unsigned long lo; unsigned long hi; } uuid_time_t; static OSErr GenRandomEthernet(uuid_address_t *addr); static OSErr GetEthernetAddr(uuid_address_t *addr); static OSErr ReadPrefData(void); /* * Preferences file management */ static uuid_address_t GSavedENetAddr = {{0, 0, 0, 0, 0, 0}}; static uuid_time_t GLastTime = {0, 0}; /* Clock state info */ static unsigned short GTimeAdjust = 0; static unsigned short GClockSeq = 0; /* * Internal structure of universal unique IDs (UUIDs). * * There are three "variants" of UUIDs that this code knows about. The * variant #0 is what was defined in the 1989 HP/Apollo Network Computing * Architecture (NCA) specification and implemented in NCS 1.x and DECrpc * v1. Variant #1 is what was defined for the joint HP/DEC specification * for the OSF (in DEC's "UID Architecture Functional Specification Version * X1.0.4") and implemented in NCS 2.0, DECrpc v2, and OSF 1.0 DCE RPC. * Variant #2 is defined by Microsoft. * * This code creates only variant #1 UUIDs. * * The three UUID variants can exist on the same wire because they have * distinct values in the 3 MSB bits of octet 8 (see table below). Do * NOT confuse the version number with these 3 bits. (Note the distinct * use of the terms "version" and "variant".) Variant #0 had no version * field in it. Changes to variant #1 (should any ever need to be made) * can be accomodated using the current form's 4 bit version field. * * The UUID record structure MUST NOT contain padding between fields. * The total size = 128 bits. * * To minimize confusion about bit assignment within octets, the UUID * record definition is defined only in terms of fields that are integral * numbers of octets. * * Depending on the network data representation, the multi-octet unsigned * integer fields are subject to byte swapping when communicated between * dissimilar endian machines. Note that all three UUID variants have * the same record structure; this allows this byte swapping to occur. * (The ways in which the contents of the fields are generated can and * do vary.) * * The following information applies to variant #1 UUIDs: * * The lowest addressed octet contains the global/local bit and the * unicast/multicast bit, and is the first octet of the address transmitted * on an 802.3 LAN. * * The adjusted time stamp is split into three fields, and the clockSeq * is split into two fields. * * |<------------------------- 32 bits -------------------------->| * * +--------------------------------------------------------------+ * | low 32 bits of time | 0-3 .time_low * +-------------------------------+------------------------------- * | mid 16 bits of time | 4-5 .time_mid * +-------+-----------------------+ * | vers. | hi 12 bits of time | 6-7 .time_hi_and_version * +-------+-------+---------------+ * |Res| clkSeqHi | 8 .clock_seq_hi_and_reserved * +---------------+ * | clkSeqLow | 9 .clock_seq_low * +---------------+----------...-----+ * | node ID | 8-16 .node * +--------------------------...-----+ * * -------------------------------------------------------------------------- * * The structure layout of all three UUID variants is fixed for all time. * I.e., the layout consists of a 32 bit int, 2 16 bit ints, and 8 8 * bit ints. The current form version field does NOT determine/affect * the layout. This enables us to do certain operations safely on the * variants of UUIDs without regard to variant; this increases the utility * of this code even as the version number changes (i.e., this code does * NOT need to check the version field). * * The "Res" field in the octet #8 is the so-called "reserved" bit-field * and determines whether or not the uuid is a old, current or other * UUID as follows: * * MS-bit 2MS-bit 3MS-bit Variant * --------------------------------------------- * 0 x x 0 (NCS 1.5) * 1 0 x 1 (DCE 1.0 RPC) * 1 1 0 2 (Microsoft) * 1 1 1 unspecified * * -------------------------------------------------------------------------- * * Internal structure of variant #0 UUIDs * * The first 6 octets are the number of 4 usec units of time that have * passed since 1/1/80 0000 GMT. The next 2 octets are reserved for * future use. The next octet is an address family. The next 7 octets * are a host ID in the form allowed by the specified address family. * * Note that while the family field (octet 8) was originally conceived * of as being able to hold values in the range [0..255], only [0..13] * were ever used. Thus, the 2 MSB of this field are always 0 and are * used to distinguish old and current UUID forms. * * +--------------------------------------------------------------+ * | high 32 bits of time | 0-3 .time_high * +-------------------------------+------------------------------- * | low 16 bits of time | 4-5 .time_low * +-------+-----------------------+ * | reserved | 6-7 .reserved * +---------------+---------------+ * | family | 8 .family * +---------------+----------...-----+ * | node ID | 9-16 .node * +--------------------------...-----+ * */ /*************************************************************************** * * Local definitions * **************************************************************************/ static const long uuid_c_version = 1; /* * local defines used in uuid bit-diddling */ #define HI_WORD(w) ((w) >> 16) #define RAND_MASK 0x3fff /* same as CLOCK_SEQ_LAST */ #define TIME_MID_MASK 0x0000ffff #define TIME_HIGH_MASK 0x0fff0000 #define TIME_HIGH_SHIFT_COUNT 16 /* * The following was modified in order to prevent overlap because * our clock is (theoretically) accurate to 1us (or 1s in CarbonLib) */ #define MAX_TIME_ADJUST 9 /* Max adjust before tick */ #define CLOCK_SEQ_LOW_MASK 0xff #define CLOCK_SEQ_HIGH_MASK 0x3f00 #define CLOCK_SEQ_HIGH_SHIFT_COUNT 8 #define CLOCK_SEQ_FIRST 1 #define CLOCK_SEQ_LAST 0x3fff /* same as RAND_MASK */ /* * Note: If CLOCK_SEQ_BIT_BANG == true, then we can avoid the modulo * operation. This should save us a divide instruction and speed * things up. */ #ifndef CLOCK_SEQ_BIT_BANG #define CLOCK_SEQ_BIT_BANG 1 #endif #if CLOCK_SEQ_BIT_BANG #define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) & CLOCK_SEQ_LAST) #else #define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) % (CLOCK_SEQ_LAST+1)) #endif #define UUID_VERSION_BITS (uuid_c_version << 12) #define UUID_RESERVED_BITS 0x80 #define IS_OLD_UUID(uuid) (((uuid)->clock_seq_hi_and_reserved & 0xc0) != 0x80) /**************************************************************************** * * local data declarations * ****************************************************************************/ typedef struct { unsigned long lo; unsigned long hi; } unsigned64_t; /* * declarations used in UTC time calculations */ static uuid_time_t time_now = {0, 0}; /* utc time as of last query */ //static uuid_time_t time_last; /* utc time last time I looked */ //static unsigned short time_adjust; /* 'adjustment' to ensure uniqness */ //static unsigned short clock_seq; /* 'adjustment' for backwards clocks*/ /* * true_random variables */ static unsigned long rand_m = 0; /* multiplier */ static unsigned long rand_ia = 0; /* adder #1 */ static unsigned long rand_ib = 0; /* adder #2 */ static unsigned long rand_irand = 0; /* random value */ typedef enum { uuid_e_less_than, uuid_e_equal_to, uuid_e_greater_than } uuid_compval_t; /**************************************************************************** * * local function declarations * ****************************************************************************/ /* * I N I T * * Startup initialization routine for UUID module. */ static OSErr init (void); /* * T R U E _ R A N D O M _ I N I T */ static void true_random_init (void); /* * T R U E _ R A N D O M */ static unsigned short true_random (void); /* * N E W _ C L O C K _ S E Q * * Ensure clock_seq is up-to-date * * Note: clock_seq is architected to be 14-bits (unsigned) but * I've put it in here as 16-bits since there isn't a * 14-bit unsigned integer type (yet) */ static void new_clock_seq ( unsigned short * /*clock_seq*/); /* * T I M E _ C M P * * Compares two UUID times (64-bit DEC UID UTC values) */ static uuid_compval_t time_cmp ( uuid_time_t * /*time1*/, uuid_time_t * /*time2*/ ); /************************************************************************/ /* */ /* New Routines */ /* */ /************************************************************************/ /* * saved copy of our IEEE 802 address for quick reference */ static uuid_address_t saved_addr = {{0, 0, 0, 0, 0, 0}}; static int got_address = false; static int last_addr_result = false; /* **++ ** ** ROUTINE NAME: uuid_get_address ** ** SCOPE: PUBLIC ** ** DESCRIPTION: ** ** Return our IEEE 802 address. ** ** This function is not really "public", but more like the SPI functions ** -- available but not part of the official API. We've done this so ** that other subsystems (of which there are hopefully few or none) ** that need the IEEE 802 address can use this function rather than ** duplicating the gore it does (or more specifically, the gore that ** "uuid__get_os_address" does). ** ** INPUTS: none ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** addr IEEE 802 address ** ** status return status value ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: none ** ** SIDE EFFECTS: none ** **-- **/ static int uuid_get_address(uuid_address_t *addr) { /* * just return address we determined previously if we've * already got one */ if (got_address) { memmove (addr, &saved_addr, sizeof (uuid_address_t)); return last_addr_result; } /* * Otherwise, call the system specific routine. */ last_addr_result = GetEthernetAddr(addr); /* * Was this an error? If so, I need to generate a random * sequence to use in place of an Ethernet address. */ if (last_addr_result) { last_addr_result = GenRandomEthernet(addr); } got_address = true; if (last_addr_result == 0) { /* On no error copy */ memmove (&saved_addr, addr, sizeof (uuid_address_t)); } return last_addr_result; } static OSErr GenRandomEthernet(uuid_address_t *addr) { unsigned int i; for (i = 0; i < 6; i++) { addr->eaddr[i] = (unsigned char)(true_random() & 0xff); } return 0; } __private_extern__ CFStringRef __CFCopyRegularEthernetAddrString(void) { uuid_address_t addr; static CFStringRef string = NULL; static Boolean lookedUpAddr = false; if (!lookedUpAddr) { // dont use the cache, since a random enet addr might have been put in it if (GetEthernetAddr(&addr) == 0) { 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]); } lookedUpAddr = true; } return (string ? CFRetain(string) : NULL); } __private_extern__ CFStringRef __CFCopyEthernetAddrString(void) { uuid_address_t addr; static CFStringRef string = NULL; static Boolean lookedUpAddr = false; if (!lookedUpAddr) { // dont use the cache, since a random enet addr might have been put in it if (GetEthernetAddr(&addr) == 0) { 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]); } lookedUpAddr = true; } return (string ? CFRetain(string) : NULL); } /***************************************************************************** * * Macro definitions * ****************************************************************************/ /* * ensure we've been initialized */ static int uuid_init_done = false; #define EmptyArg #define UUID_VERIFY_INIT(Arg) \ if (! uuid_init_done) \ { \ init (status); \ if (*status != uuid_s_ok) \ { \ return Arg; \ } \ } /* * Check the reserved bits to make sure the UUID is of the known structure. */ #define CHECK_STRUCTURE(uuid) \ ( \ (((uuid)->clock_seq_hi_and_reserved & 0x80) == 0x00) || /* var #0 */ \ (((uuid)->clock_seq_hi_and_reserved & 0xc0) == 0x80) || /* var #1 */ \ (((uuid)->clock_seq_hi_and_reserved & 0xe0) == 0xc0) /* var #2 */ \ ) /* * The following macros invoke CHECK_STRUCTURE(), check that the return * value is okay and if not, they set the status variable appropriately * and return either a boolean false, nothing (for void procedures), * or a value passed to the macro. This has been done so that checking * can be done more simply and values are returned where appropriate * to keep compilers happy. * * bCHECK_STRUCTURE - returns boolean false * vCHECK_STRUCTURE - returns nothing (void) * rCHECK_STRUCTURE - returns 'r' macro parameter */ #define bCHECK_STRUCTURE(uuid, status) \ { \ if (!CHECK_STRUCTURE (uuid)) \ { \ *(status) = uuid_s_bad_version; \ return (false); \ } \ } #define vCHECK_STRUCTURE(uuid, status) \ { \ if (!CHECK_STRUCTURE (uuid)) \ { \ *(status) = uuid_s_bad_version; \ return; \ } \ } #define rCHECK_STRUCTURE(uuid, status, result) \ { \ if (!CHECK_STRUCTURE (uuid)) \ { \ *(status) = uuid_s_bad_version; \ return (result); \ } \ } /* * Define constant designation difference in Unix and DTSS base times: * DTSS UTC base time is October 15, 1582. * Unix base time is January 1, 1970. */ #define uuid_c_os_base_time_diff_lo 0x13814000 #define uuid_c_os_base_time_diff_hi 0x01B21DD2 #ifndef UUID_C_100NS_PER_SEC #define UUID_C_100NS_PER_SEC 10000000 #endif #ifndef UUID_C_100NS_PER_USEC #define UUID_C_100NS_PER_USEC 10 #endif /* * UADD_UVLW_2_UVLW - macro to add two unsigned 64-bit long integers * (ie. add two unsigned 'very' long words) * * Important note: It is important that this macro accommodate (and it does) * invocations where one of the addends is also the sum. * * This macro was snarfed from the DTSS group and was originally: * * UTCadd - macro to add two UTC times * * add lo and high order longword separately, using sign bits of the low-order * longwords to determine carry. sign bits are tested before addition in two * cases - where sign bits match. when the addend sign bits differ the sign of * the result is also tested: * * sign sign * addend 1 addend 2 carry? * * 1 1 true * 1 0 true if sign of sum clear * 0 1 true if sign of sum clear * 0 0 false */ #define UADD_UVLW_2_UVLW(add1, add2, sum) \ if (!(((add1)->lo&0x80000000UL) ^ ((add2)->lo&0x80000000UL))) \ { \ if (((add1)->lo&0x80000000UL)) \ { \ (sum)->lo = (add1)->lo + (add2)->lo ; \ (sum)->hi = (add1)->hi + (add2)->hi+1 ; \ } \ else \ { \ (sum)->lo = (add1)->lo + (add2)->lo ; \ (sum)->hi = (add1)->hi + (add2)->hi ; \ } \ } \ else \ { \ (sum)->lo = (add1)->lo + (add2)->lo ; \ (sum)->hi = (add1)->hi + (add2)->hi ; \ if (!((sum)->lo&0x80000000UL)) \ (sum)->hi++ ; \ } /* * UADD_UW_2_UVLW - macro to add a 16-bit unsigned integer to * a 64-bit unsigned integer * * Note: see the UADD_UVLW_2_UVLW() macro * */ #define UADD_UW_2_UVLW(add1, add2, sum) \ { \ (sum)->hi = (add2)->hi; \ if ((add2)->lo & 0x80000000UL) \ { \ (sum)->lo = (*add1) + (add2)->lo; \ if (!((sum)->lo & 0x80000000UL)) \ { \ (sum)->hi++; \ } \ } \ else \ { \ (sum)->lo = (*add1) + (add2)->lo; \ } \ } /* * U U I D _ _ G E T _ O S _ T I M E * * Get OS time - contains platform-specific code. */ static const double utc_conversion_factor = 429.4967296; // 2^32 / 10^7 static void uuid__get_os_time (uuid_time_t * uuid_time) { unsigned64_t utc, os_basetime_diff; CFAbsoluteTime at = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; double utc_at = at / utc_conversion_factor; /* Convert 'at' in double seconds to 100ns units in utc */ utc.hi = (unsigned long)utc_at; utc_at -= (double)utc.hi; utc_at *= utc_conversion_factor; utc_at *= 10000000.0; utc.lo = (unsigned long)utc_at; /* * Offset between DTSS formatted times and Unix formatted times. */ os_basetime_diff.lo = uuid_c_os_base_time_diff_lo; os_basetime_diff.hi = uuid_c_os_base_time_diff_hi; UADD_UVLW_2_UVLW (&utc, &os_basetime_diff, uuid_time); } /* **++ ** ** ROUTINE NAME: init ** ** SCOPE: INTERNAL - declared locally ** ** DESCRIPTION: ** ** Startup initialization routine for the UUID module. ** ** INPUTS: none ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status return status value ** ** uuid_s_ok ** uuid_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: sets uuid_init_done so this won't be done again ** **-- **/ static OSErr init() { /* * init the random number generator */ true_random_init(); /* * Read the preferences data from the Macintosh pref file */ ReadPrefData(); /* * Get the time. Note that I renamed 'time_last' to * GLastTime to indicate that I'm using it elsewhere as * a shared library global. */ if ((GLastTime.hi == 0) && (GLastTime.lo == 0)) { uuid__get_os_time (&GLastTime); GClockSeq = true_random(); } uuid_init_done = true; return 0; } /* ** New name: GenerateUID ** **++ ** ** ROUTINE NAME: uuid_create ** ** SCOPE: PUBLIC - declared in UUID.IDL ** ** DESCRIPTION: ** ** Create a new UUID. Note: we only know how to create the new ** and improved UUIDs. ** ** INPUTS: none ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** uuid A new UUID value ** ** status return status value ** ** uuid_s_ok ** uuid_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ /* PUBLIC void uuid_create #ifdef _DCE_PROTO_ ( uuid_t *uuid, unsigned long *status ) #else (uuid, status) uuid_t *uuid; unsigned long *status; #endif */ __private_extern__ unsigned long _CFGenerateUUID(uuid_t *uuid) { OSErr err; uuid_address_t eaddr; int got_no_time = false; if (!uuid_init_done) { err = init(); if (err) return err; } /* * get our hardware network address */ if (0 != (err = uuid_get_address(&eaddr))) return err; do { /* * get the current time */ uuid__get_os_time (&time_now); /* * do stuff like: * * o check that our clock hasn't gone backwards and handle it * accordingly with clock_seq * o check that we're not generating uuid's faster than we * can accommodate with our time_adjust fudge factor */ switch (time_cmp (&time_now, &GLastTime)) { case uuid_e_less_than: new_clock_seq (&GClockSeq); GTimeAdjust = 0; break; case uuid_e_greater_than: GTimeAdjust = 0; break; case uuid_e_equal_to: if (GTimeAdjust == MAX_TIME_ADJUST) { /* * spin your wheels while we wait for the clock to tick */ got_no_time = true; } else { GTimeAdjust++; } break; default: return kUUIDInternalError; } } while (got_no_time); GLastTime.lo = time_now.lo; GLastTime.hi = time_now.hi; if (GTimeAdjust != 0) { UADD_UW_2_UVLW (>imeAdjust, &time_now, &time_now); } /* * now construct a uuid with the information we've gathered * plus a few constants */ uuid->time_low = time_now.lo; uuid->time_mid = time_now.hi & TIME_MID_MASK; uuid->time_hi_and_version = (time_now.hi & TIME_HIGH_MASK) >> TIME_HIGH_SHIFT_COUNT; uuid->time_hi_and_version |= UUID_VERSION_BITS; uuid->clock_seq_low = GClockSeq & CLOCK_SEQ_LOW_MASK; uuid->clock_seq_hi_and_reserved = (GClockSeq & CLOCK_SEQ_HIGH_MASK) >> CLOCK_SEQ_HIGH_SHIFT_COUNT; uuid->clock_seq_hi_and_reserved |= UUID_RESERVED_BITS; memmove (uuid->node, &eaddr, sizeof (uuid_address_t)); return 0; } /***************************************************************************** * * LOCAL MATH PROCEDURES - math procedures used internally by the UUID module * ****************************************************************************/ /* ** T I M E _ C M P ** ** Compares two UUID times (64-bit UTC values) **/ static uuid_compval_t time_cmp(uuid_time_t *time1,uuid_time_t *time2) { /* * first check the hi parts */ if (time1->hi < time2->hi) return (uuid_e_less_than); if (time1->hi > time2->hi) return (uuid_e_greater_than); /* * hi parts are equal, check the lo parts */ if (time1->lo < time2->lo) return (uuid_e_less_than); if (time1->lo > time2->lo) return (uuid_e_greater_than); return (uuid_e_equal_to); } /**************************************************************************** ** ** 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 ** ***************************************************************************** ** ** This random number generator (RNG) was found in the ALGORITHMS Notesfile. ** ** (Note 16.7, July 7, 1989 by Robert (RDVAX::)Gries, Cambridge Research Lab, ** Computational Quality Group) ** ** It is really a "Multiple Prime Random Number Generator" (MPRNG) and is ** completely discussed in reference #1 (see below). ** ** References: ** 1) "The Multiple Prime Random Number Generator" by Alexander Hass ** pp. 368 to 381 in ACM Transactions on Mathematical Software, ** December, 1987 ** 2) "The Art of Computer Programming: Seminumerical Algorithms ** (vol 2)" by Donald E. Knuth, pp. 39 to 113. ** ** A summary of the notesfile entry follows: ** ** Gries discusses the two RNG's available for ULTRIX-C. The default RNG ** uses a Linear Congruential Method (very popular) and the second RNG uses ** a technique known as a linear feedback shift register. ** ** The first (default) RNG suffers from bit-cycles (patterns/repetition), ** ie. it's "not that random." ** ** While the second RNG passes all the emperical tests, there are "states" ** that become "stable", albeit contrived. ** ** Gries then presents the MPRNG and says that it passes all emperical ** tests listed in reference #2. In addition, the number of calls to the ** MPRNG before a sequence of bit position repeats appears to have a normal ** distribution. ** ** Note (mbs): I have coded the Gries's MPRNG with the same constants that ** he used in his paper. I have no way of knowing whether they are "ideal" ** for the range of numbers we are dealing with. ** ****************************************************************************/ /* ** T R U E _ R A N D O M _ I N I T ** ** Note: we "seed" the RNG with the bits from the clock and the PID ** **/ static void true_random_init (void) { uuid_time_t t; unsigned short *seedp, seed=0; /* * optimal/recommended starting values according to the reference */ static unsigned long rand_m_init = 971; static unsigned long rand_ia_init = 11113; static unsigned long rand_ib_init = 104322; static unsigned long rand_irand_init = 4181; rand_m = rand_m_init; rand_ia = rand_ia_init; rand_ib = rand_ib_init; rand_irand = rand_irand_init; /* * Generating our 'seed' value * * We start with the current time, but, since the resolution of clocks is * system hardware dependent (eg. Ultrix is 10 msec.) and most likely * coarser than our resolution (10 usec) we 'mixup' the bits by xor'ing * all the bits together. This will have the effect of involving all of * the bits in the determination of the seed value while remaining system * independent. Then for good measure to ensure a unique seed when there * are multiple processes creating UUID's on a system, we add in the PID. */ uuid__get_os_time(&t); seedp = (unsigned short *)(&t); seed ^= *seedp++; seed ^= *seedp++; seed ^= *seedp++; seed ^= *seedp++; rand_irand += seed; } /* ** T R U E _ R A N D O M ** ** Note: we return a value which is 'tuned' to our purposes. Anyone ** using this routine should modify the return value accordingly. **/ static unsigned short true_random (void) { rand_m += 7; rand_ia += 1907; rand_ib += 73939; if (rand_m >= 9973) rand_m -= 9871; if (rand_ia >= 99991) rand_ia -= 89989; if (rand_ib >= 224729) rand_ib -= 96233; rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib; return (HI_WORD (rand_irand) ^ (rand_irand & RAND_MASK)); } /***************************************************************************** * * LOCAL PROCEDURES - procedures used staticly by the UUID module * ****************************************************************************/ /* ** N E W _ C L O C K _ S E Q ** ** Ensure *clkseq is up-to-date ** ** Note: clock_seq is architected to be 14-bits (unsigned) but ** I've put it in here as 16-bits since there isn't a ** 14-bit unsigned integer type (yet) **/ static void new_clock_seq #ifdef _DCE_PROTO_ ( unsigned short *clkseq ) #else (clkseq) unsigned short *clkseq; #endif { /* * A clkseq value of 0 indicates that it hasn't been initialized. */ if (*clkseq == 0) { #ifdef UUID_NONVOLATILE_CLOCK *clkseq = uuid__read_clock(); /* read nonvolatile clock */ if (*clkseq == 0) /* still not init'd ??? */ { *clkseq = true_random(); /* yes, set random */ } #else /* * with a volatile clock, we always init to a random number */ *clkseq = true_random(); #endif } CLOCK_SEQ_BUMP (clkseq); if (*clkseq == 0) { *clkseq = *clkseq + 1; } #ifdef UUID_NONVOLATILE_CLOCK uuid_write_clock (clkseq); #endif } /* ReadPrefData * * Read the preferences data into my global variables */ static OSErr ReadPrefData(void) { /* * Zero out the saved preferences information */ memset((void *)&GSavedENetAddr, 0, sizeof(GSavedENetAddr)); memset((void *)&GLastTime, 0, sizeof(GLastTime)); GTimeAdjust = 0; GClockSeq = 0; return 0; } #if 0 // currently unused /* WritePrefData * * Write the preferences data back out to my global variables. * This gets called a couple of times. First, this is called by * my GetRandomEthernet routine if I generated a psudorandom MAC * address. Second, this is called when the library is being * terminated through the __terminate() CFM call. * * Note this does it's best attempt at writing the data out, * and relies on ReadPrefData to check for integrety of the actual * saved file. */ static void WritePrefData(void) { } #endif #if defined(__MACH__) #include <unistd.h> #include <stdio.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/sockio.h> #include <sys/uio.h> #include <sys/errno.h> #include <netinet/in.h> #include <net/if.h> #include <net/if_dl.h> #include <net/if_types.h> #if !defined(MAX) #define MAX(a, b) ((a) < (b) ? (b) : (a)) #endif #define IFR_NEXT(ifr) \ ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \ MAX(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr)))) static OSErr GetEthernetAddr(uuid_address_t *addr) { struct ifconf ifc; struct ifreq ifrbuf[30], *ifr; register int s, i; Boolean foundIt = false; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } ifc.ifc_buf = (caddr_t)ifrbuf; ifc.ifc_len = sizeof (ifrbuf); if (ioctl(s, SIOCGIFCONF, &ifc) == -1) { close(s); return -1; } for (ifr = (struct ifreq *)ifc.ifc_buf, i=0; (char *)ifr < &ifc.ifc_buf[ifc.ifc_len]; ifr = IFR_NEXT(ifr), i++) { unsigned char *p, c; if (*ifr->ifr_name == '\0') { continue; } /* * Adapt to buggy kernel implementation (> 9 of a type) */ p = &ifr->ifr_name[strlen(ifr->ifr_name)-1]; if ((c = *p) > '0'+9) { sprintf(p, "%d", c-'0'); } if (strcmp(ifr->ifr_name, "en0") == 0) { if (ifr->ifr_addr.sa_family == AF_LINK) { struct sockaddr_dl *sa = ((struct sockaddr_dl *)&ifr->ifr_addr); 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) { for (i=0, p=&sa->sdl_data[sa->sdl_nlen] ; i++ < sa->sdl_alen; p++) { addr->eaddr[i-1] = *p; } foundIt = true; break; } } } } close(s); return (foundIt ? 0 : -1); } #elif defined (__WIN32__) #error Dont know how to find Ethernet Address on Win32 // MF:!!! Maybe on Windows we should just call the COM library's UUID generator... #elif defined (__LINUX__) || defined(__FREEBSD__) static OSErr GetEthernetAddr(uuid_address_t *addr) { return -1; } #endif #undef HI_WORD #undef RAND_MASK #undef TIME_MID_MASK #undef TIME_HIGH_MASK #undef TIME_HIGH_SHIFT_COUNT #undef MAX_TIME_ADJUST #undef CLOCK_SEQ_LOW_MASK #undef CLOCK_SEQ_HIGH_MASK #undef CLOCK_SEQ_HIGH_SHIFT_COUNT #undef CLOCK_SEQ_FIRST #undef CLOCK_SEQ_LAST #undef CLOCK_SEQ_BIT_BANG #undef CLOCK_SEQ_BUMP #undef UUID_VERSION_BITS #undef UUID_RESERVED_BITS #undef IS_OLD_UUID #undef EmptyArg #undef UUID_VERIFY_INIT #undef CHECK_STRUCTURE #undef bCHECK_STRUCTURE #undef vCHECK_STRUCTURE #undef rCHECK_STRUCTURE #undef uuid_c_os_base_time_diff_lo #undef uuid_c_os_base_time_diff_hi #undef UUID_C_100NS_PER_SEC #undef UUID_C_100NS_PER_USEC #undef UADD_UVLW_2_UVLW #undef UADD_UW_2_UVLW #undef IFR_NEXT #endif