1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright (c) 2015, Joyent, Inc.
26  */
27 
28 /*
29  * The copyright in this file is taken from the original Leach
30  * & Salz UUID specification, from which this implementation
31  * is derived.
32  */
33 
34 /*
35  * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
36  * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
37  * Digital Equipment Corporation, Maynard, Mass.  Copyright (c) 1998
38  * Microsoft.  To anyone who acknowledges that this file is provided
39  * "AS IS" without any express or implied warranty: permission to use,
40  * copy, modify, and distribute this file for any purpose is hereby
41  * granted without fee, provided that the above copyright notices and
42  * this notice appears in all source code copies, and that none of the
43  * names of Open Software Foundation, Inc., Hewlett-Packard Company,
44  * or Digital Equipment Corporation be used in advertising or
45  * publicity pertaining to distribution of the software without
46  * specific, written prior permission.  Neither Open Software
47  * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
48  * Equipment Corporation makes any representations about the
49  * suitability of this software for any purpose.
50  */
51 
52 #include <uuid/uuid.h>
53 #include <stdlib.h>
54 #include <strings.h>
55 #include "uuid_misc.h"
56 
57 #define	UUCMP(u1, u2)		if (u1 != u2) return ((u1 < u2) ? -1 : 1)
58 #define	UUIDS_PER_TOD_CALL	10	/* tv_usec is multiplied by 10 */
59 
60 void		struct_to_string(uuid_t, struct uuid *);
61 void		string_to_struct(struct uuid *, uuid_t);
62 void		get_system_time(uuid_time_t *);
63 
64 /*
65  * Name:	get_current_time
66  *
67  * Description:	get-current_time -- get time as 60 bit 100ns ticks
68  *		since the beginning of unix time.
69  *		Compensate for the fact that real clock resolution is
70  *		less than 100ns.
71  *
72  * Returns:	None.
73  *
74  */
75 void
get_current_time(uuid_time_t * timestamp)76 get_current_time(uuid_time_t *timestamp)
77 {
78 	uuid_time_t		time_now;
79 	static uuid_time_t	time_last = 0;
80 	static uint16_t		uuids_this_tick = 0;
81 	int			done;
82 
83 	done = 0;
84 	while (!done) {
85 		get_system_time(&time_now);
86 
87 		/*
88 		 * if clock reading changed since last UUID generated...
89 		 */
90 		if (time_last != time_now) {
91 			/*
92 			 * reset count of uuids generated with
93 			 * this clock reading
94 			 */
95 			uuids_this_tick = 0;
96 			done = 1;
97 		} else {
98 			uuids_this_tick++;
99 			if (uuids_this_tick < UUIDS_PER_TOD_CALL)
100 				done = 1;
101 		}
102 		/*
103 		 * too many UUIDs for this gettimeofday call; spin
104 		 */
105 	}
106 	time_last = time_now;
107 	/*
108 	 * add the count of uuids to low order bits of the clock reading
109 	 */
110 	*timestamp = time_now + uuids_this_tick;
111 }
112 
113 /*
114  * Name:	get_random
115  *
116  * Description:	Gets a random number.
117  *
118  * Returns:	nbytes of random information.
119  *
120  */
121 uint16_t
get_random(void)122 get_random(void)
123 {
124 	return (arc4random_uniform(UINT16_MAX));
125 }
126 
127 /*
128  * Name:	uuid_compare
129  *
130  * Description: Compares 2 uuid strings
131  *
132  * Returns:	-1 if u1 < u2, 1 if u1 > u2 and 0 if both are equal
133  */
134 int
uuid_compare(uuid_t uu1,uuid_t uu2)135 uuid_compare(uuid_t uu1, uuid_t uu2)
136 {
137 
138 	struct uuid	uuid1, uuid2;
139 
140 	string_to_struct(&uuid1, uu1);
141 	string_to_struct(&uuid2, uu2);
142 	UUCMP(uuid1.time_low, uuid2.time_low);
143 	UUCMP(uuid1.time_mid, uuid2.time_mid);
144 	UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
145 	UUCMP(uuid1.clock_seq_hi_and_reserved, uuid2.clock_seq_hi_and_reserved);
146 	UUCMP(uuid1.clock_seq_low, uuid2.clock_seq_low);
147 	return (memcmp(uuid1.node_addr, uuid2.node_addr, 6));
148 }
149 
150 /*
151  * Name:	get_system_time
152  *
153  * Description:	system dependent call to get the current system time.
154  *		Returned as 100ns ticks since Oct 15, 1582, but
155  *		resolution may be less than 100ns.
156  *
157  * Returns:	None
158  */
159 void
get_system_time(uuid_time_t * uuid_time)160 get_system_time(uuid_time_t *uuid_time)
161 {
162 	struct timeval tp;
163 
164 	(void) gettimeofday(&tp, (struct timezone *)0);
165 
166 	/*
167 	 * Offset between UUID formatted times and Unix formatted times.
168 	 * UUID UTC base time is October 15, 1582.
169 	 * Unix base time is January 1, 1970.
170 	 */
171 	*uuid_time = (uint64_t)tp.tv_sec * 10000000;
172 	*uuid_time += tp.tv_usec * 10;
173 	*uuid_time += 0x01B21DD213814000ULL;
174 }
175