]> git.saurik.com Git - apple/cf.git/blame - Base.subproj/uuid.c
CF-299.32.tar.gz
[apple/cf.git] / Base.subproj / uuid.c
CommitLineData
9ce05555
A
1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/* uuid.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
28*/
29
30#if defined(__WIN32__)
31/* _CFGenerateUUID function just calls the COM library's UUID generator
32 * (Aleksey Dukhnyakov)
33 */
34#include <windows.h>
35#include <ole2.h>
36#include <objbase.h>
37
38unsigned long _CFGenerateUUID(uuid_t *uuid) {
39 RPC_STATUS rStatus;
40
41 /* call GetScode() function to get RPC_STATUS, because
42 * CoCreateGuid(uuid) function return HRESULT type
43 */
44 rStatus = GetScode(CoCreateGuid(uuid));
45
46 /* We accept only following results RPC_S_OK, RPC_S_UUID_LOCAL_ONLY
47 */
48 if ( rStatus == RPC_S_UUID_NO_ADDRESS)
49 return rStatus;
50
51 return 0;
52};
53
54#else
55
56/* uuid.c
57 *
58 * Modifications made by William Woody to make this thing
59 * work on the Macintosh.
60 */
61
62/*
63 *
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
79 * purpose.
80 *
81 */
82/*
83 */
84/*
85**
86** NAME:
87**
88** uuid.c
89**
90** FACILITY:
91**
92** UUID
93**
94** ABSTRACT:
95**
96** UUID - routines that manipulate uuid's
97**
98**
99*/
100
101#include <CoreFoundation/CFBase.h>
102#include <CoreFoundation/CFDate.h>
103#include "CFInternal.h"
104#include <string.h>
105
106
107/* uuid_t already defined in RPCDCE.H (WIN32 header)
108 * (Aleksey Dukhnyakov)
109 */
110#if defined(__WIN32__)
111#define UUID_T_DEFINED 1
112#endif
113
114#if !defined(UUID_T_DEFINED)
115#define UUID_T_DEFINED 1
116
117/* uuid
118 *
119 * Universal Unique ID. Note this definition will result is a 16-byte
120 * structure regardless what platform it is on.
121 */
122
123struct uuid_t {
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];
130};
131
132typedef struct uuid_t uuid_t;
133
134#endif
135
136enum {
137 kUUIDInternalError = -21001,
138 kUUIDInvalidString = -21002
139};
140
141extern unsigned long _CFGenerateUUID(uuid_t *uuid);
142
143typedef struct
144{
145 unsigned char eaddr[6]; /* 6 bytes of ethernet hardware address */
146} uuid_address_t;
147
148typedef struct {
149 unsigned long lo;
150 unsigned long hi;
151} uuid_time_t;
152
153static OSErr GenRandomEthernet(uuid_address_t *addr);
154static OSErr GetEthernetAddr(uuid_address_t *addr);
155
156static OSErr ReadPrefData(void);
157
158/*
159 * Preferences file management
160 */
161
162static uuid_address_t GSavedENetAddr = {{0, 0, 0, 0, 0, 0}};
163static uuid_time_t GLastTime = {0, 0}; /* Clock state info */
164static unsigned short GTimeAdjust = 0;
165static unsigned short GClockSeq = 0;
166
167
168/*
169 * Internal structure of universal unique IDs (UUIDs).
170 *
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.
178 *
179 * This code creates only variant #1 UUIDs.
180 *
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.
187 *
188 * The UUID record structure MUST NOT contain padding between fields.
189 * The total size = 128 bits.
190 *
191 * To minimize confusion about bit assignment within octets, the UUID
192 * record definition is defined only in terms of fields that are integral
193 * numbers of octets.
194 *
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
200 * do vary.)
201 *
202 * The following information applies to variant #1 UUIDs:
203 *
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
206 * on an 802.3 LAN.
207 *
208 * The adjusted time stamp is split into three fields, and the clockSeq
209 * is split into two fields.
210 *
211 * |<------------------------- 32 bits -------------------------->|
212 *
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
221 * +---------------+
222 * | clkSeqLow | 9 .clock_seq_low
223 * +---------------+----------...-----+
224 * | node ID | 8-16 .node
225 * +--------------------------...-----+
226 *
227 * --------------------------------------------------------------------------
228 *
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).
236 *
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
239 * UUID as follows:
240 *
241 * MS-bit 2MS-bit 3MS-bit Variant
242 * ---------------------------------------------
243 * 0 x x 0 (NCS 1.5)
244 * 1 0 x 1 (DCE 1.0 RPC)
245 * 1 1 0 2 (Microsoft)
246 * 1 1 1 unspecified
247 *
248 * --------------------------------------------------------------------------
249 *
250 * Internal structure of variant #0 UUIDs
251 *
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.
256 *
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.
261 *
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 * +--------------------------...-----+
273 *
274 */
275
276/***************************************************************************
277 *
278 * Local definitions
279 *
280 **************************************************************************/
281
282static const long uuid_c_version = 1;
283
284/*
285 * local defines used in uuid bit-diddling
286 */
287#define HI_WORD(w) ((w) >> 16)
288#define RAND_MASK 0x3fff /* same as CLOCK_SEQ_LAST */
289
290#define TIME_MID_MASK 0x0000ffff
291#define TIME_HIGH_MASK 0x0fff0000
292#define TIME_HIGH_SHIFT_COUNT 16
293
294/*
295 * The following was modified in order to prevent overlap because
296 * our clock is (theoretically) accurate to 1us (or 1s in CarbonLib)
297 */
298
299
300#define MAX_TIME_ADJUST 9 /* Max adjust before tick */
301
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 */
307
308/*
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
311 * things up.
312 */
313
314#ifndef CLOCK_SEQ_BIT_BANG
315#define CLOCK_SEQ_BIT_BANG 1
316#endif
317
318#if CLOCK_SEQ_BIT_BANG
319#define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) & CLOCK_SEQ_LAST)
320#else
321#define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) % (CLOCK_SEQ_LAST+1))
322#endif
323
324#define UUID_VERSION_BITS (uuid_c_version << 12)
325#define UUID_RESERVED_BITS 0x80
326
327#define IS_OLD_UUID(uuid) (((uuid)->clock_seq_hi_and_reserved & 0xc0) != 0x80)
328
329/****************************************************************************
330 *
331 * local data declarations
332 *
333 ****************************************************************************/
334
335typedef struct {
336 unsigned long lo;
337 unsigned long hi;
338} unsigned64_t;
339
340/*
341 * declarations used in UTC time calculations
342 */
343
344static 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*/
348
349/*
350 * true_random variables
351 */
352
353static unsigned long rand_m = 0; /* multiplier */
354static unsigned long rand_ia = 0; /* adder #1 */
355static unsigned long rand_ib = 0; /* adder #2 */
356static unsigned long rand_irand = 0; /* random value */
357
358typedef enum
359{
360 uuid_e_less_than, uuid_e_equal_to, uuid_e_greater_than
361} uuid_compval_t;
362
363
364
365
366/****************************************************************************
367 *
368 * local function declarations
369 *
370 ****************************************************************************/
371
372/*
373 * I N I T
374 *
375 * Startup initialization routine for UUID module.
376 */
377
378static OSErr init (void);
379
380/*
381 * T R U E _ R A N D O M _ I N I T
382 */
383
384static void true_random_init (void);
385
386/*
387 * T R U E _ R A N D O M
388 */
389static unsigned short true_random (void);
390
391
392/*
393 * N E W _ C L O C K _ S E Q
394 *
395 * Ensure clock_seq is up-to-date
396 *
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)
400 */
401static void new_clock_seq ( unsigned short * /*clock_seq*/);
402
403
404/*
405 * T I M E _ C M P
406 *
407 * Compares two UUID times (64-bit DEC UID UTC values)
408 */
409static uuid_compval_t time_cmp (
410 uuid_time_t * /*time1*/,
411 uuid_time_t * /*time2*/
412 );
413
414
415/************************************************************************/
416/* */
417/* New Routines */
418/* */
419/************************************************************************/
420
421/*
422 * saved copy of our IEEE 802 address for quick reference
423 */
424
425static uuid_address_t saved_addr = {{0, 0, 0, 0, 0, 0}};
426static int got_address = false;
427static int last_addr_result = false;
428
429
430/*
431**++
432**
433** ROUTINE NAME: uuid_get_address
434**
435** SCOPE: PUBLIC
436**
437** DESCRIPTION:
438**
439** Return our IEEE 802 address.
440**
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).
447**
448** INPUTS: none
449**
450** INPUTS/OUTPUTS: none
451**
452** OUTPUTS:
453**
454** addr IEEE 802 address
455**
456** status return status value
457**
458** IMPLICIT INPUTS: none
459**
460** IMPLICIT OUTPUTS: none
461**
462** FUNCTION VALUE: none
463**
464** SIDE EFFECTS: none
465**
466**--
467**/
468
469static int uuid_get_address(uuid_address_t *addr)
470{
471
472 /*
473 * just return address we determined previously if we've
474 * already got one
475 */
476
477 if (got_address) {
478 memmove (addr, &saved_addr, sizeof (uuid_address_t));
479 return last_addr_result;
480 }
481
482 /*
483 * Otherwise, call the system specific routine.
484 */
485
486 last_addr_result = GetEthernetAddr(addr);
487
488 /*
489 * Was this an error? If so, I need to generate a random
490 * sequence to use in place of an Ethernet address.
491 */
492 if (last_addr_result) {
493 last_addr_result = GenRandomEthernet(addr);
494 }
495
496 got_address = true;
497 if (last_addr_result == 0) {
498 /* On no error copy */
499 memmove (&saved_addr, addr, sizeof (uuid_address_t));
500 }
501 return last_addr_result;
502}
503
504static OSErr GenRandomEthernet(uuid_address_t *addr) {
505 unsigned int i;
506 for (i = 0; i < 6; i++) {
507 addr->eaddr[i] = (unsigned char)(true_random() & 0xff);
508 }
509 return 0;
510}
511
512__private_extern__ CFStringRef __CFCopyRegularEthernetAddrString(void) {
513 uuid_address_t addr;
514 static CFStringRef string = NULL;
515 static Boolean lookedUpAddr = false;
516
517 if (!lookedUpAddr) {
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]);
521 }
522 lookedUpAddr = true;
523 }
524 return (string ? CFRetain(string) : NULL);
525}
526
527__private_extern__ CFStringRef __CFCopyEthernetAddrString(void) {
528 uuid_address_t addr;
529 static CFStringRef string = NULL;
530 static Boolean lookedUpAddr = false;
531
532 if (!lookedUpAddr) {
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]);
536 }
537 lookedUpAddr = true;
538 }
539 return (string ? CFRetain(string) : NULL);
540}
541
542/*****************************************************************************
543 *
544 * Macro definitions
545 *
546 ****************************************************************************/
547
548/*
549 * ensure we've been initialized
550 */
551static int uuid_init_done = false;
552
553#define EmptyArg
554#define UUID_VERIFY_INIT(Arg) \
555 if (! uuid_init_done) \
556 { \
557 init (status); \
558 if (*status != uuid_s_ok) \
559 { \
560 return Arg; \
561 } \
562 }
563
564/*
565 * Check the reserved bits to make sure the UUID is of the known structure.
566 */
567
568#define CHECK_STRUCTURE(uuid) \
569( \
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 */ \
573)
574
575/*
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.
582 *
583 * bCHECK_STRUCTURE - returns boolean false
584 * vCHECK_STRUCTURE - returns nothing (void)
585 * rCHECK_STRUCTURE - returns 'r' macro parameter
586 */
587
588#define bCHECK_STRUCTURE(uuid, status) \
589{ \
590 if (!CHECK_STRUCTURE (uuid)) \
591 { \
592 *(status) = uuid_s_bad_version; \
593 return (false); \
594 } \
595}
596
597#define vCHECK_STRUCTURE(uuid, status) \
598{ \
599 if (!CHECK_STRUCTURE (uuid)) \
600 { \
601 *(status) = uuid_s_bad_version; \
602 return; \
603 } \
604}
605
606#define rCHECK_STRUCTURE(uuid, status, result) \
607{ \
608 if (!CHECK_STRUCTURE (uuid)) \
609 { \
610 *(status) = uuid_s_bad_version; \
611 return (result); \
612 } \
613}
614
615
616/*
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.
620 */
621#define uuid_c_os_base_time_diff_lo 0x13814000
622#define uuid_c_os_base_time_diff_hi 0x01B21DD2
623
624#ifndef UUID_C_100NS_PER_SEC
625#define UUID_C_100NS_PER_SEC 10000000
626#endif
627
628#ifndef UUID_C_100NS_PER_USEC
629#define UUID_C_100NS_PER_USEC 10
630#endif
631
632
633
634
635
636/*
637 * UADD_UVLW_2_UVLW - macro to add two unsigned 64-bit long integers
638 * (ie. add two unsigned 'very' long words)
639 *
640 * Important note: It is important that this macro accommodate (and it does)
641 * invocations where one of the addends is also the sum.
642 *
643 * This macro was snarfed from the DTSS group and was originally:
644 *
645 * UTCadd - macro to add two UTC times
646 *
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:
651 *
652 * sign sign
653 * addend 1 addend 2 carry?
654 *
655 * 1 1 true
656 * 1 0 true if sign of sum clear
657 * 0 1 true if sign of sum clear
658 * 0 0 false
659 */
660#define UADD_UVLW_2_UVLW(add1, add2, sum) \
661 if (!(((add1)->lo&0x80000000UL) ^ ((add2)->lo&0x80000000UL))) \
662 { \
663 if (((add1)->lo&0x80000000UL)) \
664 { \
665 (sum)->lo = (add1)->lo + (add2)->lo ; \
666 (sum)->hi = (add1)->hi + (add2)->hi+1 ; \
667 } \
668 else \
669 { \
670 (sum)->lo = (add1)->lo + (add2)->lo ; \
671 (sum)->hi = (add1)->hi + (add2)->hi ; \
672 } \
673 } \
674 else \
675 { \
676 (sum)->lo = (add1)->lo + (add2)->lo ; \
677 (sum)->hi = (add1)->hi + (add2)->hi ; \
678 if (!((sum)->lo&0x80000000UL)) \
679 (sum)->hi++ ; \
680 }
681
682/*
683 * UADD_UW_2_UVLW - macro to add a 16-bit unsigned integer to
684 * a 64-bit unsigned integer
685 *
686 * Note: see the UADD_UVLW_2_UVLW() macro
687 *
688 */
689#define UADD_UW_2_UVLW(add1, add2, sum) \
690{ \
691 (sum)->hi = (add2)->hi; \
692 if ((add2)->lo & 0x80000000UL) \
693 { \
694 (sum)->lo = (*add1) + (add2)->lo; \
695 if (!((sum)->lo & 0x80000000UL)) \
696 { \
697 (sum)->hi++; \
698 } \
699 } \
700 else \
701 { \
702 (sum)->lo = (*add1) + (add2)->lo; \
703 } \
704}
705
706/*
707 * U U I D _ _ G E T _ O S _ T I M E
708 *
709 * Get OS time - contains platform-specific code.
710 */
711
712static const double utc_conversion_factor = 429.4967296; // 2^32 / 10^7
713
714static void uuid__get_os_time (uuid_time_t * uuid_time)
715{
716 unsigned64_t utc,
717 os_basetime_diff;
718 CFAbsoluteTime at = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
719 double utc_at = at / utc_conversion_factor;
720
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;
727
728 /*
729 * Offset between DTSS formatted times and Unix formatted times.
730 */
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);
734
735}
736
737/*
738**++
739**
740** ROUTINE NAME: init
741**
742** SCOPE: INTERNAL - declared locally
743**
744** DESCRIPTION:
745**
746** Startup initialization routine for the UUID module.
747**
748** INPUTS: none
749**
750** INPUTS/OUTPUTS: none
751**
752** OUTPUTS:
753**
754** status return status value
755**
756** uuid_s_ok
757** uuid_s_coding_error
758**
759** IMPLICIT INPUTS: none
760**
761** IMPLICIT OUTPUTS: none
762**
763** FUNCTION VALUE: void
764**
765** SIDE EFFECTS: sets uuid_init_done so this won't be done again
766**
767**--
768**/
769
770static OSErr init()
771{
772 /*
773 * init the random number generator
774 */
775
776 true_random_init();
777
778 /*
779 * Read the preferences data from the Macintosh pref file
780 */
781
782 ReadPrefData();
783
784 /*
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.
788 */
789
790 if ((GLastTime.hi == 0) && (GLastTime.lo == 0)) {
791 uuid__get_os_time (&GLastTime);
792 GClockSeq = true_random();
793 }
794 uuid_init_done = true;
795 return 0;
796}
797
798/*
799** New name: GenerateUID
800**
801**++
802**
803** ROUTINE NAME: uuid_create
804**
805** SCOPE: PUBLIC - declared in UUID.IDL
806**
807** DESCRIPTION:
808**
809** Create a new UUID. Note: we only know how to create the new
810** and improved UUIDs.
811**
812** INPUTS: none
813**
814** INPUTS/OUTPUTS: none
815**
816** OUTPUTS:
817**
818** uuid A new UUID value
819**
820** status return status value
821**
822** uuid_s_ok
823** uuid_s_coding_error
824**
825** IMPLICIT INPUTS: none
826**
827** IMPLICIT OUTPUTS: none
828**
829** FUNCTION VALUE: void
830**
831** SIDE EFFECTS: none
832**
833**--
834**/
835
836/*
837PUBLIC void uuid_create
838#ifdef _DCE_PROTO_
839(
840 uuid_t *uuid,
841 unsigned long *status
842)
843#else
844(uuid, status)
845uuid_t *uuid;
846unsigned long *status;
847#endif
848*/
849
850__private_extern__ unsigned long _CFGenerateUUID(uuid_t *uuid)
851{
852 OSErr err;
853 uuid_address_t eaddr;
854 int got_no_time = false;
855
856 if (!uuid_init_done) {
857 err = init();
858 if (err) return err;
859 }
860 /*
861 * get our hardware network address
862 */
863
864 if (0 != (err = uuid_get_address(&eaddr))) return err;
865
866 do
867 {
868 /*
869 * get the current time
870 */
871 uuid__get_os_time (&time_now);
872
873 /*
874 * do stuff like:
875 *
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
880 */
881 switch (time_cmp (&time_now, &GLastTime))
882 {
883 case uuid_e_less_than:
884 new_clock_seq (&GClockSeq);
885 GTimeAdjust = 0;
886 break;
887 case uuid_e_greater_than:
888 GTimeAdjust = 0;
889 break;
890 case uuid_e_equal_to:
891 if (GTimeAdjust == MAX_TIME_ADJUST)
892 {
893 /*
894 * spin your wheels while we wait for the clock to tick
895 */
896 got_no_time = true;
897 }
898 else
899 {
900 GTimeAdjust++;
901 }
902 break;
903 default:
904 return kUUIDInternalError;
905 }
906 } while (got_no_time);
907
908 GLastTime.lo = time_now.lo;
909 GLastTime.hi = time_now.hi;
910
911 if (GTimeAdjust != 0)
912 {
913 UADD_UW_2_UVLW (&GTimeAdjust, &time_now, &time_now);
914 }
915
916 /*
917 * now construct a uuid with the information we've gathered
918 * plus a few constants
919 */
920 uuid->time_low = time_now.lo;
921 uuid->time_mid = time_now.hi & TIME_MID_MASK;
922
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;
926
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;
930
931 uuid->clock_seq_hi_and_reserved |= UUID_RESERVED_BITS;
932
933 memmove (uuid->node, &eaddr, sizeof (uuid_address_t));
934
935 return 0;
936}
937
938/*****************************************************************************
939 *
940 * LOCAL MATH PROCEDURES - math procedures used internally by the UUID module
941 *
942 ****************************************************************************/
943
944/*
945** T I M E _ C M P
946**
947** Compares two UUID times (64-bit UTC values)
948**/
949
950static uuid_compval_t time_cmp(uuid_time_t *time1,uuid_time_t *time2)
951{
952 /*
953 * first check the hi parts
954 */
955 if (time1->hi < time2->hi) return (uuid_e_less_than);
956 if (time1->hi > time2->hi) return (uuid_e_greater_than);
957
958 /*
959 * hi parts are equal, check the lo parts
960 */
961 if (time1->lo < time2->lo) return (uuid_e_less_than);
962 if (time1->lo > time2->lo) return (uuid_e_greater_than);
963
964 return (uuid_e_equal_to);
965}
966
967
968
969/****************************************************************************
970**
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
972**
973*****************************************************************************
974**
975** This random number generator (RNG) was found in the ALGORITHMS Notesfile.
976**
977** (Note 16.7, July 7, 1989 by Robert (RDVAX::)Gries, Cambridge Research Lab,
978** Computational Quality Group)
979**
980** It is really a "Multiple Prime Random Number Generator" (MPRNG) and is
981** completely discussed in reference #1 (see below).
982**
983** References:
984** 1) "The Multiple Prime Random Number Generator" by Alexander Hass
985** pp. 368 to 381 in ACM Transactions on Mathematical Software,
986** December, 1987
987** 2) "The Art of Computer Programming: Seminumerical Algorithms
988** (vol 2)" by Donald E. Knuth, pp. 39 to 113.
989**
990** A summary of the notesfile entry follows:
991**
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.
995**
996** The first (default) RNG suffers from bit-cycles (patterns/repetition),
997** ie. it's "not that random."
998**
999** While the second RNG passes all the emperical tests, there are "states"
1000** that become "stable", albeit contrived.
1001**
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
1005** distribution.
1006**
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.
1010**
1011****************************************************************************/
1012
1013/*
1014** T R U E _ R A N D O M _ I N I T
1015**
1016** Note: we "seed" the RNG with the bits from the clock and the PID
1017**
1018**/
1019
1020static void true_random_init (void)
1021{
1022 uuid_time_t t;
1023 unsigned short *seedp, seed=0;
1024
1025
1026 /*
1027 * optimal/recommended starting values according to the reference
1028 */
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;
1033
1034 rand_m = rand_m_init;
1035 rand_ia = rand_ia_init;
1036 rand_ib = rand_ib_init;
1037 rand_irand = rand_irand_init;
1038
1039 /*
1040 * Generating our 'seed' value
1041 *
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.
1049 */
1050 uuid__get_os_time(&t);
1051 seedp = (unsigned short *)(&t);
1052 seed ^= *seedp++;
1053 seed ^= *seedp++;
1054 seed ^= *seedp++;
1055 seed ^= *seedp++;
1056 rand_irand += seed;
1057}
1058
1059/*
1060** T R U E _ R A N D O M
1061**
1062** Note: we return a value which is 'tuned' to our purposes. Anyone
1063** using this routine should modify the return value accordingly.
1064**/
1065
1066static unsigned short true_random (void)
1067{
1068 rand_m += 7;
1069 rand_ia += 1907;
1070 rand_ib += 73939;
1071
1072 if (rand_m >= 9973) rand_m -= 9871;
1073 if (rand_ia >= 99991) rand_ia -= 89989;
1074 if (rand_ib >= 224729) rand_ib -= 96233;
1075
1076 rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib;
1077
1078 return (HI_WORD (rand_irand) ^ (rand_irand & RAND_MASK));
1079}
1080
1081/*****************************************************************************
1082 *
1083 * LOCAL PROCEDURES - procedures used staticly by the UUID module
1084 *
1085 ****************************************************************************/
1086
1087/*
1088** N E W _ C L O C K _ S E Q
1089**
1090** Ensure *clkseq is up-to-date
1091**
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)
1095**/
1096
1097static void new_clock_seq
1098#ifdef _DCE_PROTO_
1099(
1100 unsigned short *clkseq
1101)
1102#else
1103(clkseq)
1104unsigned short *clkseq;
1105#endif
1106{
1107 /*
1108 * A clkseq value of 0 indicates that it hasn't been initialized.
1109 */
1110 if (*clkseq == 0)
1111 {
1112#ifdef UUID_NONVOLATILE_CLOCK
1113 *clkseq = uuid__read_clock(); /* read nonvolatile clock */
1114 if (*clkseq == 0) /* still not init'd ??? */
1115 {
1116 *clkseq = true_random(); /* yes, set random */
1117 }
1118#else
1119 /*
1120 * with a volatile clock, we always init to a random number
1121 */
1122 *clkseq = true_random();
1123#endif
1124 }
1125
1126 CLOCK_SEQ_BUMP (clkseq);
1127 if (*clkseq == 0)
1128 {
1129 *clkseq = *clkseq + 1;
1130 }
1131
1132#ifdef UUID_NONVOLATILE_CLOCK
1133 uuid_write_clock (clkseq);
1134#endif
1135}
1136
1137
1138
1139/* ReadPrefData
1140 *
1141 * Read the preferences data into my global variables
1142 */
1143
1144static OSErr ReadPrefData(void)
1145{
1146 /*
1147 * Zero out the saved preferences information
1148 */
1149
1150 memset((void *)&GSavedENetAddr, 0, sizeof(GSavedENetAddr));
1151 memset((void *)&GLastTime, 0, sizeof(GLastTime));
1152 GTimeAdjust = 0;
1153 GClockSeq = 0;
1154
1155 return 0;
1156}
1157
1158#if 0
1159// currently unused
1160
1161/* WritePrefData
1162 *
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.
1168 *
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
1171 * saved file.
1172 */
1173
1174static void WritePrefData(void)
1175{
1176}
1177
1178#endif
1179
1180
1181#if defined(__MACH__)
1182
1183#include <unistd.h>
1184#include <stdio.h>
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>
1190
1191#include <netinet/in.h>
1192#include <net/if.h>
1193#include <net/if_dl.h>
1194#include <net/if_types.h>
1195
1196#if !defined(MAX)
1197#define MAX(a, b) ((a) < (b) ? (b) : (a))
1198#endif
1199
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))))
1203
1204static OSErr GetEthernetAddr(uuid_address_t *addr) {
1205 struct ifconf ifc;
1206 struct ifreq ifrbuf[30], *ifr;
1207 register int s, i;
1208 Boolean foundIt = false;
1209
1210 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
1211 return -1;
1212 }
1213
1214 ifc.ifc_buf = (caddr_t)ifrbuf;
1215 ifc.ifc_len = sizeof (ifrbuf);
1216 if (ioctl(s, SIOCGIFCONF, &ifc) == -1) {
1217 close(s);
1218 return -1;
1219 }
1220
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;
1223
1224 if (*ifr->ifr_name == '\0') {
1225 continue;
1226 }
1227 /*
1228 * Adapt to buggy kernel implementation (> 9 of a type)
1229 */
1230
1231 p = &ifr->ifr_name[strlen(ifr->ifr_name)-1];
1232 if ((c = *p) > '0'+9) {
1233 sprintf(p, "%d", c-'0');
1234 }
1235
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;
1242 }
1243 foundIt = true;
1244 break;
1245 }
1246 }
1247 }
1248 }
1249 close(s);
1250 return (foundIt ? 0 : -1);
1251}
1252
1253#elif defined (__WIN32__)
1254
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...
1257
1258#elif defined (__LINUX__) || defined(__FREEBSD__)
1259
1260static OSErr GetEthernetAddr(uuid_address_t *addr) {
1261 return -1;
1262}
1263
1264#endif
1265
1266#undef HI_WORD
1267#undef RAND_MASK
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
1281#undef IS_OLD_UUID
1282#undef EmptyArg
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
1294#undef IFR_NEXT
1295
1296#endif
1297