idnits 2.17.00 (12 Aug 2021) /tmp/idnits28909/draft-leach-uuids-guids-01.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- ** Looks like you're using RFC 2026 boilerplate. This must be updated to follow RFC 3978/3979, as updated by RFC 4748. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- ** Missing expiration date. The document expiration date should appear on the first and last page. ** The document seems to lack a 1id_guidelines paragraph about Internet-Drafts being working documents. ** The document seems to lack a 1id_guidelines paragraph about the list of current Internet-Drafts. ** The document seems to lack a 1id_guidelines paragraph about the list of Shadow Directories. == The page length should not exceed 58 lines per page, but there was 27 longer pages, the longest (page 1) being 61 lines Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The document seems to lack an IANA Considerations section. (See Section 2.2 of https://www.ietf.org/id-info/checklist for how to handle the case when there are no actions for IANA.) ** The document seems to lack separate sections for Informative/Normative References. All references will be assumed normative when checking for downward references. ** The abstract seems to contain references ([2], [1]), which it shouldn't. Please replace those with straight textual mentions of the documents in question. ** The document seems to lack a both a reference to RFC 2119 and the recommended RFC 2119 boilerplate, even if it appears to use RFC 2119 keywords. RFC 2119 keyword, line 280: '... they MAY use local time instead of U...' RFC 2119 keyword, line 281: '...tem. This is NOT RECOMMENDED, however,...' RFC 2119 keyword, line 310: '...e clock sequence MUST be originally (i...' RFC 2119 keyword, line 314: '...he initial value MUST NOT be correlate...' RFC 2119 keyword, line 428: '...nterval, the UUID service MUST either:...' (3 more instances...) Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the RFC 3978 Section 5.4 Copyright Line does not match the current year == Line 231 has weird spacing: '...version uns...' == Line 235 has weird spacing: '...nd_rese unsig...' == Line 546 has weird spacing: '... 0-3 of time_...' == Line 548 has weird spacing: '... 0-1 of time_...' == Line 550 has weird spacing: '... 0-1 of time_...' == (4 more instances...) -- The document seems to lack a disclaimer for pre-RFC5378 work, but may have content which was first submitted before 10 November 2008. If you have contacted all the original authors and they are all willing to grant the BCP78 rights to the IETF Trust, then this is fine, and you can ignore this comment. If not, you may need to add the pre-RFC5378 disclaimer. (See the Legal Provisions document at https://trustee.ietf.org/license-info for more information.) -- The document date (February 4, 1998) is 8865 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) == Missing Reference: '6' is mentioned on line 1247, but not defined == Missing Reference: '16' is mentioned on line 1365, but not defined == Missing Reference: '0' is mentioned on line 1277, but not defined == Missing Reference: '257' is mentioned on line 1370, but not defined -- Possible downref: Non-RFC (?) normative reference: ref. '1' -- Possible downref: Non-RFC (?) normative reference: ref. '2' ** Downref: Normative reference to an Informational RFC: RFC 1321 (ref. '3') -- Possible downref: Non-RFC (?) normative reference: ref. '4' Summary: 10 errors (**), 0 flaws (~~), 12 warnings (==), 6 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 Network Working Group Paul J. Leach, Microsoft 3 INTERNET-DRAFT Rich Salz, Certco 4 5 Category: Standards Track 6 Expires August 4, 1998 February 4, 1998 8 UUIDs and GUIDs 10 STATUS OF THIS MEMO 12 This document is an Internet-Draft. Internet-Drafts are working 13 documents of the Internet Engineering Task Force (IETF), its areas, 14 and its working groups. Note that other groups may also distribute 15 working documents as Internet-Drafts. 17 Internet-Drafts are draft documents valid for a maximum of six months 18 and may be updated, replaced, or obsoleted by other documents at any 19 time. It is inappropriate to use Internet-Drafts as reference 20 material or to cite them other than as "work in progress". 22 To learn the current status of any Internet-Draft, please check the 23 "1id-abstracts.txt" listing contained in the Internet-Drafts Shadow 24 Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe), 25 munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or 26 ftp.isi.edu (US West Coast). 28 Distribution of this document is unlimited. Please send comments to 29 the authors or the CIFS mailing list at . 30 Discussions of the mailing list are archived at 31 "-" "-" 613 "-" 614 615 "-" 616 time_low = 4* 617 time_mid = 2* 618 time_high_and_version = 2* 619 clock_seq_and_reserved = 620 clock_seq_low = 621 node = 6* 623 hexDigit = 624 "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" 625 | "a" | "b" | "c" | "d" | "e" | "f" 626 | "A" | "B" | "C" | "D" | "E" | "F" 628 The following is an example of the string representation of a UUID: 630 f81d4fae-7dec-11d0-a765-00a0c91e6bf6 632 3.6 Comparing UUIDs for equality 634 Consider each field of the UUID to be an unsigned integer as shown in 635 the table in section 3.1. Then, to compare a pair of UUIDs, 636 arithmetically compare the corresponding fields from each UUID in 637 order of significance and according to their data type. Two UUIDs are 638 equal if and only if all the corresponding fields are equal. 640 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 642 Note: as a practical matter, on many systems comparison of two UUIDs 643 for equality can be performed simply by comparing the 128 bits of 644 their in-memory representation considered as a 128 bit unsigned 645 integer. Here, it is presumed that by the time the in-memory 646 representation is obtained the appropriate byte-order 647 canonicalizations have been carried out. 649 3.7 Comparing UUIDs for relative order 651 Two UUIDs allocated according to the same variant can also be ordered 652 lexicographically. For the UUID variant herein defined, the first of 653 two UUIDs follows the second if the most significant field in which 654 the UUIDs differ is greater for the first UUID. The first of a pair 655 of UUIDs precedes the second if the most significant field in which 656 the UUIDs differ is greater for the second UUID. 658 3.8 Byte order of UUIDs 660 UUIDs may be transmitted in many different forms, some of which may 661 be dependent on the presentation or application protocol where the 662 UUID may be used. In such cases, the order, sizes and byte orders of 663 the UUIDs fields on the wire will depend on the relevant presentation 664 or application protocol. However, it is strongly RECOMMENDED that 665 the order of the fields conform with ordering set out in section 3.1 666 above. Furthermore, the payload size of each field in the application 667 or presentation protocol MUST be large enough that no information 668 lost in the process of encoding them for transmission. 670 In the absence of explicit application or presentation protocol 671 specification to the contrary, a UUID is encoded as a 128-bit object, 672 as follows: the fields are encoded as 16 octets, with the sizes and 673 order of the fields defined in section 3.1, and with each field 674 encoded with the Most Significant Byte first (also known as network 675 byte order). 677 0 1 2 3 678 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 679 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 680 | time_low | 681 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 682 | time_mid | time_hi_and_version | 683 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 684 |clk_seq_hi_res | clk_seq_low | node (0-1) | 685 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 686 | node (2-5) | 687 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 688 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 690 4. Node IDs when no IEEE 802 network card is available 692 If a system wants to generate UUIDs but has no IEE 802 compliant 693 network card or other source of IEEE 802 addresses, then this section 694 describes how to generate one. 696 The ideal solution is to obtain a 47 bit cryptographic quality random 697 number, and use it as the low 47 bits of the node ID, with the most 698 significant bit of the first octet of the node ID set to 1. This bit 699 is the unicast/multicast bit, which will never be set in IEEE 802 700 addresses obtained from network cards; hence, there can never be a 701 conflict between UUIDs generated by machines with and without network 702 cards. 704 If a system does not have a primitive to generate cryptographic 705 quality random numbers, then in most systems there are usually a 706 fairly large number of sources of randomness available from which one 707 can be generated. Such sources are system specific, but often 708 include: 710 - the percent of memory in use 711 - the size of main memory in bytes 712 - the amount of free main memory in bytes 713 - the size of the paging or swap file in bytes 714 - free bytes of paging or swap file 715 - the total size of user virtual address space in bytes 716 - the total available user address space bytes 717 - the size of boot disk drive in bytes 718 - the free disk space on boot drive in bytes 719 - the current time 720 - the amount of time since the system booted 721 - the individual sizes of files in various system directories 722 - the creation, last read, and modification times of files in various 723 system directories 724 - the utilization factors of various system resources (heap, etc.) 725 - current mouse cursor position 726 - current caret position 727 - current number of running processes, threads 728 - handles or IDs of the desktop window and the active window 729 - the value of stack pointer of the caller 730 - the process and thread ID of caller 731 - various processor architecture specific performance counters 732 (instructions executed, cache misses, TLB misses) 734 (Note that it precisely the above kinds of sources of randomness that 735 are used to seed cryptographic quality random number generators on 736 systems without special hardware for their construction.) 738 In addition, items such as the computer's name and the name of the 739 operating system, while not strictly speaking random, will help 740 differentiate the results from those obtained by other systems. 742 The exact algorithm to generate a node ID using these data is system 743 specific, because both the data available and the functions to obtain 744 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 746 them are often very system specific. However, assuming that one can 747 concatenate all the values from the randomness sources into a buffer, 748 and that a cryptographic hash function such as MD5 [3] is available, 749 then any 6 bytes of the MD5 hash of the buffer, with the multicast 750 bit (the high bit of the first byte) set will be an appropriately 751 random node ID. 753 Other hash functions, such as SHA-1 [4], can also be used. The only 754 requirement is that the result be suitably random _ in the sense that 755 the outputs from a set uniformly distributed inputs are themselves 756 uniformly distributed, and that a single bit change in the input can 757 be expected to cause half of the output bits to change. 759 5. Obtaining IEEE 802 addresses 761 At the time of writing, the following URL 763 http://standards.ieee.org/db/oui/forms/ 765 contains information on how to obtain an IEEE 802 address block. At 766 the time of writing, the cost is $1250 US. 768 6. Security Considerations 770 It should not be assumed that UUIDs are hard to guess; they should 771 not be used as capabilities. 773 7. Acknowledgements 775 This document draws heavily on the OSF DCE specification for UUIDs. 776 Ted Ts'o provided helpful comments, especially on the byte ordering 777 section which we mostly plagiarized from a proposed wording he 778 supplied (all errors in that section are our responsibility, 779 however). 781 8. References 783 [1] Lisa Zahn, et. al., Network Computing Architecture, Prentice 784 Hall, Englewood Cliffs, NJ, 1990 786 [2] DCE: Remote Procedure Call, Open Group CAE Specification C309 787 ISBN 1-85912-041-5 28cm. 674p. pbk. 1,655g. 8/94 789 [3] R. Rivest, RFC 1321, "The MD5 Message-Digest Algorithm", 790 04/16/1992. 792 [4] NIST FIPS PUB 180-1, "Secure Hash Standard," National Institute 793 of Standards and Technology, U.S. Department of Commerce, DRAFT, May 794 31, 1994. 796 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 798 9. Authors' addresses 800 Paul J. Leach 801 Microsoft 802 1 Microsoft Way 803 Redmond, WA, 98052, U.S.A. 804 paulle@microsoft.com 805 Tel. 425 882 8080 806 Fax. 425 936 7329 808 Rich Salz 809 100 Cambridge Park Drive 810 Cambridge MA 02140 811 salzr@certco.com 812 Tel. 617 499 4075 813 Fax. 617 576 0019 815 10. Notice 817 The IETF takes no position regarding the validity or scope of any 818 intellectual property or other rights that might be claimed to 819 pertain to the implementation or use of the technology described in 820 this document or the extent to which any license under such rights 821 might or might not be available; neither does it represent that it 822 has made any effort to identify any such rights. Information on the 823 IETF's procedures with respect to rights in standards-track and 824 standards-related documentation can be found in BCP-11. Copies of 825 claims of rights made available for publication and any assurances of 826 licenses to be made available, or the result of an attempt made to 827 obtain a general license or permission for the use of such 828 proprietary rights by implementors or users of this specification can 829 be obtained from the IETF Secretariat. 831 The IETF invites any interested party to bring to its attention any 832 copyrights, patents or patent applications, or other proprietary 833 rights which may cover technology that may be required to practice 834 this standard. Please address the information to the IETF Executive 835 Director. 837 11. Full Copyright Statement 839 Copyright (C) The Internet Society 1997. All Rights Reserved. 841 This document and translations of it may be copied and furnished to 842 others, and derivative works that comment on or otherwise explain it 843 or assist in its implementation may be prepared, copied, published 844 and distributed, in whole or in part, without restriction of any 845 kind, provided that the above copyright notice and this paragraph are 846 included on all such copies and derivative works. However, this 847 document itself may not be modified in any way, such as by removing 848 the copyright notice or references to the Internet Society or other 849 Internet organizations, except as needed for the purpose of 850 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 852 developing Internet standards in which case the procedures for 853 copyrights defined in the Internet Standards process must be 854 followed, or as required to translate it into languages other than 855 English. 857 The limited permissions granted above are perpetual and will not be 858 revoked by the Internet Society or its successors or assigns. 860 This document and the information contained herein is provided on an 861 "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING 862 TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING 863 BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION 864 HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF 865 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 867 Appendix A _ UUID Sample Implementation 869 This implementation consists of 5 files: uuid.h, uuid.c, sysdep.h, 870 sysdep.c and utest.c. The uuid.* files are the system independent 871 implementation of the UUID generation algorithms described above, 872 with all the optimizations described above except efficient state 873 sharing across processes included. The code has been tested on Linux 874 (Red Hat 4.0) with GCC (2.7.2), and Windows NT 4.0 with VC++ 5.0. The 875 code assumes 64 bit integer support, which makes it a lot clearer. 877 All the following source files should be considered to have the 878 following copyright notice included: 880 copyrt.h 882 /* 883 ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. 884 ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & 885 ** Digital Equipment Corporation, Maynard, Mass. 886 ** Copyright (c) 1998 Microsoft. 887 ** To anyone who acknowledges that this file is provided "AS IS" 888 ** without any express or implied warranty: permission to use, copy, 889 ** modify, and distribute this file for any purpose is hereby 890 ** granted without fee, provided that the above copyright notices and 891 ** this notice appears in all source code copies, and that none of 892 ** the names of Open Software Foundation, Inc., Hewlett-Packard 893 ** Company, or Digital Equipment Corporation be used in advertising 894 ** or publicity pertaining to distribution of the software without 895 ** specific, written prior permission. Neither Open Software 896 ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital 897 Equipment 898 ** Corporation makes any representations about the suitability of 899 ** this software for any purpose. 900 */ 902 uuid.h 903 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 905 #include "copyrt.h" 906 #undef uuid_t 907 typedef struct _uuid_t { 908 unsigned32 time_low; 909 unsigned16 time_mid; 910 unsigned16 time_hi_and_version; 911 unsigned8 clock_seq_hi_and_reserved; 912 unsigned8 clock_seq_low; 913 byte node[6]; 914 } uuid_t; 916 /* uuid_create -- generate a UUID */ 917 int uuid_create(uuid_t * uuid); 919 /* uuid_create_from_name -- create a UUID using a "name" 920 from a "name space" */ 921 void uuid_create_from_name( 922 uuid_t * uuid, /* resulting UUID */ 923 uuid_t nsid, /* UUID to serve as context, so identical 924 names from different name spaces generate 925 different UUIDs */ 926 void * name, /* the name from which to generate a UUID */ 927 int namelen /* the length of the name */ 928 ); 930 /* uuid_compare -- Compare two UUID's "lexically" and return 931 -1 u1 is lexically before u2 932 0 u1 is equal to u2 933 1 u1 is lexically after u2 934 Note: lexical ordering is not temporal ordering! 935 */ 936 int uuid_compare(uuid_t *u1, uuid_t *u2); 938 uuid.c 940 #include "copyrt.h" 941 #include 942 #include 943 #include 944 #include 945 #include "sysdep.h" 946 #include "uuid.h" 948 /* various forward declarations */ 949 static int read_state(unsigned16 *clockseq, uuid_time_t *timestamp, 950 uuid_node_t * node); 951 static void write_state(unsigned16 clockseq, uuid_time_t timestamp, 952 uuid_node_t node); 953 static void format_uuid_v1(uuid_t * uuid, unsigned16 clockseq, 954 uuid_time_t timestamp, uuid_node_t node); 955 static void format_uuid_v3(uuid_t * uuid, unsigned char hash[16]); 956 static void get_current_time(uuid_time_t * timestamp); 957 static unsigned16 true_random(void); 958 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 960 /* uuid_create -- generator a UUID */ 961 int uuid_create(uuid_t * uuid) { 962 uuid_time_t timestamp, last_time; 963 unsigned16 clockseq; 964 uuid_node_t node; 965 uuid_node_t last_node; 966 int f; 968 /* acquire system wide lock so we're alone */ 969 LOCK; 971 /* get current time */ 972 get_current_time(×tamp); 974 /* get node ID */ 975 get_ieee_node_identifier(&node); 977 /* get saved state from NV storage */ 978 f = read_state(&clockseq, &last_time, &last_node); 980 /* if no NV state, or if clock went backwards, or node ID changed 981 (e.g., net card swap) change clockseq */ 982 if (!f || memcmp(&node, &last_node, sizeof(uuid_node_t))) 983 clockseq = true_random(); 984 else if (timestamp < last_time) 985 clockseq++; 987 /* stuff fields into the UUID */ 988 format_uuid_v1(uuid, clockseq, timestamp, node); 990 /* save the state for next time */ 991 write_state(clockseq, timestamp, node); 993 UNLOCK; 994 return(1); 995 }; 997 /* format_uuid_v1 -- make a UUID from the timestamp, clockseq, 998 and node ID */ 999 void format_uuid_v1(uuid_t * uuid, unsigned16 clock_seq, uuid_time_t 1000 timestamp, uuid_node_t node) { 1001 /* Construct a version 1 uuid with the information we've gathered 1002 * plus a few constants. */ 1003 uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); 1004 uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); 1005 uuid->time_hi_and_version = (unsigned short)((timestamp >> 48) & 1006 0x0FFF); 1007 uuid->time_hi_and_version |= (1 << 12); 1008 uuid->clock_seq_low = clock_seq & 0xFF; 1009 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8; 1010 uuid->clock_seq_hi_and_reserved |= 0x80; 1011 memcpy(&uuid->node, &node, sizeof uuid->node); 1012 }; 1013 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1015 /* data type for UUID generator persistent state */ 1016 typedef struct { 1017 uuid_time_t ts; /* saved timestamp */ 1018 uuid_node_t node; /* saved node ID */ 1019 unsigned16 cs; /* saved clock sequence */ 1020 } uuid_state; 1022 static uuid_state st; 1024 /* read_state -- read UUID generator state from non-volatile store */ 1025 int read_state(unsigned16 *clockseq, uuid_time_t *timestamp, 1026 uuid_node_t *node) { 1027 FILE * fd; 1028 static int inited = 0; 1030 /* only need to read state once per boot */ 1031 if (!inited) { 1032 fd = fopen("state", "rb"); 1033 if (!fd) 1034 return (0); 1035 fread(&st, sizeof(uuid_state), 1, fd); 1036 fclose(fd); 1037 inited = 1; 1038 }; 1039 *clockseq = st.cs; 1040 *timestamp = st.ts; 1041 *node = st.node; 1042 return(1); 1043 }; 1045 /* write_state -- save UUID generator state back to non-volatile 1046 storage */ 1047 void write_state(unsigned16 clockseq, uuid_time_t timestamp, 1048 uuid_node_t node) { 1049 FILE * fd; 1050 static int inited = 0; 1051 static uuid_time_t next_save; 1053 if (!inited) { 1054 next_save = timestamp; 1055 inited = 1; 1056 }; 1057 /* always save state to volatile shared state */ 1058 st.cs = clockseq; 1059 st.ts = timestamp; 1060 st.node = node; 1061 if (timestamp >= next_save) { 1062 fd = fopen("state", "wb"); 1063 fwrite(&st, sizeof(uuid_state), 1, fd); 1064 fclose(fd); 1065 /* schedule next save for 10 seconds from now */ 1066 next_save = timestamp + (10 * 10 * 1000 * 1000); 1067 }; 1068 }; 1069 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1071 /* get-current_time -- get time as 60 bit 100ns ticks since whenever. 1072 Compensate for the fact that real clock resolution is 1073 less than 100ns. */ 1074 void get_current_time(uuid_time_t * timestamp) { 1075 uuid_time_t time_now; 1076 static uuid_time_t time_last; 1077 static unsigned16 uuids_this_tick; 1078 static int inited = 0; 1080 if (!inited) { 1081 get_system_time(&time_now); 1082 uuids_this_tick = UUIDS_PER_TICK; 1083 inited = 1; 1084 }; 1086 while (1) { 1087 get_system_time(&time_now); 1089 /* if clock reading changed since last UUID generated... */ 1090 if (time_last != time_now) { 1091 /* reset count of uuids gen'd with this clock reading */ 1092 uuids_this_tick = 0; 1093 break; 1094 }; 1095 if (uuids_this_tick < UUIDS_PER_TICK) { 1096 uuids_this_tick++; 1097 break; 1098 }; 1099 /* going too fast for our clock; spin */ 1100 }; 1101 /* add the count of uuids to low order bits of the clock reading */ 1102 *timestamp = time_now + uuids_this_tick; 1103 }; 1105 /* true_random -- generate a crypto-quality random number. 1106 This sample doesn't do that. */ 1107 static unsigned16 1108 true_random(void) 1109 { 1110 static int inited = 0; 1111 uuid_time_t time_now; 1113 if (!inited) { 1114 get_system_time(&time_now); 1115 time_now = time_now/UUIDS_PER_TICK; 1116 srand((unsigned int)(((time_now >> 32) ^ time_now)&0xffffffff)); 1117 inited = 1; 1118 }; 1120 return (rand()); 1121 } 1122 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1124 /* uuid_create_from_name -- create a UUID using a "name" from a "name 1125 space" */ 1126 void uuid_create_from_name( 1127 uuid_t * uuid, /* resulting UUID */ 1128 uuid_t nsid, /* UUID to serve as context, so identical 1129 names from different name spaces generate 1130 different UUIDs */ 1131 void * name, /* the name from which to generate a UUID */ 1132 int namelen /* the length of the name */ 1133 ) { 1134 MD5_CTX c; 1135 unsigned char hash[16]; 1136 uuid_t net_nsid; /* context UUID in network byte order */ 1138 /* put name space ID in network byte order so it hashes the same 1139 no matter what endian machine we're on */ 1140 net_nsid = nsid; 1141 htonl(net_nsid.time_low); 1142 htons(net_nsid.time_mid); 1143 htons(net_nsid.time_hi_and_version); 1145 MD5Init(&c); 1146 MD5Update(&c, &net_nsid, sizeof(uuid_t)); 1147 MD5Update(&c, name, namelen); 1148 MD5Final(hash, &c); 1150 /* the hash is in network byte order at this point */ 1151 format_uuid_v3(uuid, hash); 1152 }; 1154 /* format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number 1155 */ 1156 void format_uuid_v3(uuid_t * uuid, unsigned char hash[16]) { 1157 /* Construct a version 3 uuid with the (pseudo-)random number 1158 * plus a few constants. */ 1160 memcpy(uuid, hash, sizeof(uuid_t)); 1162 /* convert UUID to local byte order */ 1163 ntohl(uuid->time_low); 1164 ntohs(uuid->time_mid); 1165 ntohs(uuid->time_hi_and_version); 1167 /* put in the variant and version bits */ 1168 uuid->time_hi_and_version &= 0x0FFF; 1169 uuid->time_hi_and_version |= (3 << 12); 1170 uuid->clock_seq_hi_and_reserved &= 0x3F; 1171 uuid->clock_seq_hi_and_reserved |= 0x80; 1172 }; 1174 /* uuid_compare -- Compare two UUID's "lexically" and return 1175 -1 u1 is lexically before u2 1176 0 u1 is equal to u2 1177 1 u1 is lexically after u2 1178 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1180 Note: lexical ordering is not temporal ordering! 1181 */ 1182 int uuid_compare(uuid_t *u1, uuid_t *u2) 1183 { 1184 int i; 1186 #define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1; 1187 CHECK(u1->time_low, u2->time_low); 1188 CHECK(u1->time_mid, u2->time_mid); 1189 CHECK(u1->time_hi_and_version, u2->time_hi_and_version); 1190 CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved); 1191 CHECK(u1->clock_seq_low, u2->clock_seq_low) 1192 for (i = 0; i < 6; i++) { 1193 if (u1->node[i] < u2->node[i]) 1194 return -1; 1195 if (u1->node[i] > u2->node[i]) 1196 return 1; 1197 } 1198 return 0; 1199 }; 1201 sysdep.h 1203 #include "copyrt.h" 1204 /* remove the following define if you aren't running WIN32 */ 1205 #define WININC 0 1207 #ifdef WININC 1208 #include 1209 #else 1210 #include 1211 #include 1212 #include 1213 #endif 1215 /* change to point to where MD5 .h's live */ 1216 /* get MD5 sample implementation from RFC 1321 */ 1217 #include "global.h" 1218 #include "md5.h" 1220 /* set the following to the number of 100ns ticks of the actual 1221 resolution of 1222 your system's clock */ 1223 #define UUIDS_PER_TICK 1024 1225 /* Set the following to a call to acquire a system wide global lock 1226 */ 1227 #define LOCK 1228 #define UNLOCK 1230 typedef unsigned long unsigned32; 1231 typedef unsigned short unsigned16; 1232 typedef unsigned char unsigned8; 1233 typedef unsigned char byte; 1234 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1236 /* Set this to what your compiler uses for 64 bit data type */ 1237 #ifdef WININC 1238 #define unsigned64_t unsigned __int64 1239 #define I64(C) C 1240 #else 1241 #define unsigned64_t unsigned long long 1242 #define I64(C) C##LL 1243 #endif 1245 typedef unsigned64_t uuid_time_t; 1246 typedef struct { 1247 char nodeID[6]; 1248 } uuid_node_t; 1250 void get_ieee_node_identifier(uuid_node_t *node); 1251 void get_system_time(uuid_time_t *uuid_time); 1252 void get_random_info(char seed[16]); 1254 sysdep.c 1256 #include "copyrt.h" 1257 #include 1258 #include "sysdep.h" 1260 /* system dependent call to get IEEE node ID. 1261 This sample implementation generates a random node ID 1262 */ 1263 void get_ieee_node_identifier(uuid_node_t *node) { 1264 char seed[16]; 1265 FILE * fd; 1266 static inited = 0; 1267 static uuid_node_t saved_node; 1269 if (!inited) { 1270 fd = fopen("nodeid", "rb"); 1271 if (fd) { 1272 fread(&saved_node, sizeof(uuid_node_t), 1, fd); 1273 fclose(fd); 1274 } 1275 else { 1276 get_random_info(seed); 1277 seed[0] |= 0x80; 1278 memcpy(&saved_node, seed, sizeof(uuid_node_t)); 1279 fd = fopen("nodeid", "wb"); 1280 if (fd) { 1281 fwrite(&saved_node, sizeof(uuid_node_t), 1, fd); 1282 fclose(fd); 1283 }; 1284 }; 1285 inited = 1; 1286 }; 1287 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1289 *node = saved_node; 1290 }; 1292 /* system dependent call to get the current system time. 1293 Returned as 100ns ticks since Oct 15, 1582, but resolution may be 1294 less than 100ns. 1295 */ 1296 #ifdef _WINDOWS_ 1298 void get_system_time(uuid_time_t *uuid_time) { 1299 ULARGE_INTEGER time; 1301 GetSystemTimeAsFileTime((FILETIME *)&time); 1303 /* NT keeps time in FILETIME format which is 100ns ticks since 1304 Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582. 1305 The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec) 1306 + 18 years and 5 leap days. 1307 */ 1309 time.QuadPart += 1310 (unsigned __int64) (1000*1000*10) // seconds 1311 * (unsigned __int64) (60 * 60 * 24) // days 1312 * (unsigned __int64) (17+30+31+365*18+5); // # of days 1314 *uuid_time = time.QuadPart; 1316 }; 1318 void get_random_info(char seed[16]) { 1319 MD5_CTX c; 1320 typedef struct { 1321 MEMORYSTATUS m; 1322 SYSTEM_INFO s; 1323 FILETIME t; 1324 LARGE_INTEGER pc; 1325 DWORD tc; 1326 DWORD l; 1327 char hostname[MAX_COMPUTERNAME_LENGTH + 1]; 1328 } randomness; 1329 randomness r; 1331 MD5Init(&c); 1332 /* memory usage stats */ 1333 GlobalMemoryStatus(&r.m); 1334 /* random system stats */ 1335 GetSystemInfo(&r.s); 1336 /* 100ns resolution (nominally) time of day */ 1337 GetSystemTimeAsFileTime(&r.t); 1338 /* high resolution performance counter */ 1339 QueryPerformanceCounter(&r.pc); 1340 /* milliseconds since last boot */ 1341 r.tc = GetTickCount(); 1342 r.l = MAX_COMPUTERNAME_LENGTH + 1; 1343 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1345 GetComputerName(r.hostname, &r.l ); 1346 MD5Update(&c, &r, sizeof(randomness)); 1347 MD5Final(seed, &c); 1348 }; 1349 #else 1351 void get_system_time(uuid_time_t *uuid_time) 1352 { 1353 struct timeval tp; 1355 gettimeofday(&tp, (struct timezone *)0); 1357 /* Offset between UUID formatted times and Unix formatted times. 1358 UUID UTC base time is October 15, 1582. 1359 Unix base time is January 1, 1970. 1360 */ 1361 *uuid_time = (tp.tv_sec * 10000000) + (tp.tv_usec * 10) + 1362 I64(0x01B21DD213814000); 1363 }; 1365 void get_random_info(char seed[16]) { 1366 MD5_CTX c; 1367 typedef struct { 1368 struct sysinfo s; 1369 struct timeval t; 1370 char hostname[257]; 1371 } randomness; 1372 randomness r; 1374 MD5Init(&c); 1375 sysinfo(&r.s); 1376 gettimeofday(&r.t, (struct timezone *)0); 1377 gethostname(r.hostname, 256); 1378 MD5Update(&c, &r, sizeof(randomness)); 1379 MD5Final(seed, &c); 1380 }; 1382 #endif 1384 utest.c 1386 #include "copyrt.h" 1387 #include "sysdep.h" 1388 #include 1389 #include "uuid.h" 1391 uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ 1392 0x6ba7b810, 1393 0x9dad, 1394 0x11d1, 1395 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 1396 }; 1397 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1399 /* puid -- print a UUID */ 1400 void puid(uuid_t u); 1402 /* Simple driver for UUID generator */ 1403 void main(int argc, char **argv) { 1404 uuid_t u; 1405 int f; 1407 uuid_create(&u); 1408 printf("uuid_create() -> "); puid(u); 1410 f = uuid_compare(&u, &u); 1411 printf("uuid_compare(u,u): %d\n", f); /* should be 0 */ 1412 f = uuid_compare(&u, &NameSpace_DNS); 1413 printf("uuid_compare(u, NameSpace_DNS): %d\n", f); /* s.b. 1 */ 1414 f = uuid_compare(&NameSpace_DNS, &u); 1415 printf("uuid_compare(NameSpace_DNS, u): %d\n", f); /* s.b. -1 */ 1417 uuid_create_from_name(&u, NameSpace_DNS, "www.widgets.com", 15); 1418 printf("uuid_create_from_name() -> "); puid(u); 1419 }; 1421 void puid(uuid_t u) { 1422 int i; 1424 printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid, 1425 u.time_hi_and_version, u.clock_seq_hi_and_reserved, 1426 u.clock_seq_low); 1427 for (i = 0; i < 6; i++) 1428 printf("%2.2x", u.node[i]); 1429 printf("\n"); 1430 }; 1432 Appendix B _ Sample output of utest 1434 uuid_create() -> 7d444840-9dc0-11d1-b245-5ffdce74fad2 1435 uuid_compare(u,u): 0 1436 uuid_compare(u, NameSpace_DNS): 1 1437 uuid_compare(NameSpace_DNS, u): -1 1438 uuid_create_from_name() -> e902893a-9d22-3c7e-a7b8-d6e313b71d9f 1440 Appendix C _ Some name space IDs 1442 This appendix lists the name space IDs for some potentially 1443 interesting name spaces, as initialized C structures and in the 1444 string representation defined in section 3.5 1446 uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ 1447 0x6ba7b810, 1448 0x9dad, 1449 0x11d1, 1450 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 1451 }; 1452 Internet-Draft UUIDs and GUIDs (DRAFT) 02/04/98 1454 uuid_t NameSpace_URL = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */ 1455 0x6ba7b811, 1456 0x9dad, 1457 0x11d1, 1458 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 1459 }; 1461 uuid_t NameSpace_OID = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */ 1462 0x6ba7b812, 1463 0x9dad, 1464 0x11d1, 1465 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 1466 }; 1468 uuid_t NameSpace_X500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */ 1469 0x6ba7b814, 1470 0x9dad, 1471 0x11d1, 1472 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 1473 };