/ Sources / UUID / uuid.c
uuid.c
  1  /*
  2   * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  3   *
  4   * %Begin-Header%
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, and the entire permission notice in its entirety,
 10   *    including the disclaimer of warranties.
 11   * 2. Redistributions in binary form must reproduce the above copyright
 12   *    notice, this list of conditions and the following disclaimer in the
 13   *    documentation and/or other materials provided with the distribution.
 14   * 3. The name of the author may not be used to endorse or promote
 15   *    products derived from this software without specific prior
 16   *    written permission.
 17   * 
 18   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 19   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 20   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
 21   * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
 22   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 23   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 24   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 25   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 26   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 28   * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
 29   * DAMAGE.
 30   * %End-Header%
 31   */
 32  
 33  #include "uuid.h"
 34  
 35  #include <stdint.h>
 36  #include <string.h>
 37  #include <fcntl.h>
 38  #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
 39  #include <unistd.h>
 40  #elif defined(_WIN32)
 41  #include <io.h>
 42  #define WIN32_LEAN_AND_MEAN
 43  #include <Windows.h>
 44  #include <bcrypt.h>
 45  #endif
 46  #include <stdio.h>
 47  
 48  #if TARGET_OS_MAC
 49  #include <sys/socket.h>
 50  #include <sys/time.h>
 51  
 52  #include <mach/mach_time.h>
 53  
 54  #include <net/if.h>
 55  #include <net/if_dl.h>
 56  #include <net/if_types.h>
 57  
 58  static inline void nanotime(struct timespec *tv) {
 59      uint64_t now = mach_absolute_time();
 60      tv->tv_sec = now / 1000000000;
 61      tv->tv_nsec = now - (tv->tv_sec * 1000000000);
 62  }
 63  
 64  #elif TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI
 65  #include <time.h>
 66  
 67  static inline void nanotime(struct timespec *tv) {
 68  	clock_gettime(CLOCK_MONOTONIC, tv);
 69  }
 70  
 71  #elif TARGET_OS_WINDOWS
 72  #include <time.h>
 73  
 74  static inline void nanotime(struct timespec *tv) {
 75    FILETIME ftTime;
 76  
 77    GetSystemTimePreciseAsFileTime(&ftTime);
 78  
 79    uint64_t Value = (((uint64_t)ftTime.dwHighDateTime << 32) | ftTime.dwLowDateTime);
 80  
 81    tv->tv_sec = Value / 1000000000;
 82    tv->tv_nsec = Value - (tv->tv_sec * 1000000000);
 83  }
 84  #endif
 85  
 86  #if TARGET_OS_WINDOWS
 87  static inline void read_random(void *buffer, unsigned numBytes) {
 88      BCryptGenRandom(NULL, buffer, numBytes,
 89                      BCRYPT_RNG_USE_ENTROPY_IN_BUFFER | BCRYPT_USE_SYSTEM_PREFERRED_RNG);
 90  }
 91  #elif TARGET_OS_WASI
 92  #include <sys/random.h>
 93  
 94  static inline void read_random(void *buffer, unsigned numBytes) {
 95    getentropy(buffer, numBytes);
 96  }
 97  #else
 98  static inline void read_random(void *buffer, unsigned numBytes) {
 99      int fd = open("/dev/urandom", O_RDONLY);
100      read(fd, buffer, numBytes);
101      close(fd);
102  }
103  #endif
104  
105  
106  UUID_DEFINE(UUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
107  
108  static void
109  read_node(uint8_t *node)
110  {
111  #if NETWORKING
112  	struct ifnet *ifp;
113  	struct ifaddr *ifa;
114  	struct sockaddr_dl *sdl;
115  
116  	ifnet_head_lock_shared();
117  	TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
118  		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
119  			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
120  			if (sdl && sdl->sdl_family == AF_LINK && sdl->sdl_type == IFT_ETHER) {
121  				memcpy(node, LLADDR(sdl), 6);
122  				ifnet_head_done();
123  				return;
124  			}
125  		}
126  	}
127  	ifnet_head_done();
128  #endif /* NETWORKING */
129  
130  	read_random(node, 6);
131  	node[0] |= 0x01;
132  }
133  
134  static uint64_t
135  read_time(void)
136  {
137  	struct timespec tv;
138  
139  	nanotime(&tv);
140  
141  	return (tv.tv_sec * 10000000ULL) + (tv.tv_nsec / 100ULL) + 0x01B21DD213814000ULL;
142  }
143  
144  void
145  uuid_clear(uuid_t uu)
146  {
147  	memset(uu, 0, sizeof(uuid_t));
148  }
149  
150  int
151  uuid_compare(const uuid_t uu1, const uuid_t uu2)
152  {
153  	return memcmp(uu1, uu2, sizeof(uuid_t));
154  }
155  
156  void
157  uuid_copy(uuid_t dst, const uuid_t src)
158  {
159  	memcpy(dst, src, sizeof(uuid_t));
160  }
161  
162  void
163  uuid_generate_random(uuid_t out)
164  {
165  	read_random(out, sizeof(uuid_t));
166  
167  	out[6] = (out[6] & 0x0F) | 0x40;
168  	out[8] = (out[8] & 0x3F) | 0x80;
169  }
170  
171  void
172  uuid_generate_time(uuid_t out)
173  {
174  	uint64_t time;
175  
176  	read_node(&out[10]);
177  	read_random(&out[8], 2);
178  
179  	time = read_time();
180  	out[0] = (uint8_t)(time >> 24);
181  	out[1] = (uint8_t)(time >> 16);
182  	out[2] = (uint8_t)(time >> 8);
183  	out[3] = (uint8_t)time;
184  	out[4] = (uint8_t)(time >> 40);
185  	out[5] = (uint8_t)(time >> 32);
186  	out[6] = (uint8_t)(time >> 56);
187  	out[7] = (uint8_t)(time >> 48);
188   
189  	out[6] = (out[6] & 0x0F) | 0x10;
190  	out[8] = (out[8] & 0x3F) | 0x80;
191  }
192  
193  void
194  uuid_generate(uuid_t out)
195  {
196  	uuid_generate_random(out);
197  }
198  
199  int
200  uuid_is_null(const uuid_t uu)
201  {
202  	return !memcmp(uu, UUID_NULL, sizeof(uuid_t));
203  }
204  
205  int
206  uuid_parse(const uuid_string_t in, uuid_t uu)
207  {
208  	int n = 0;
209  
210  	sscanf(in,
211  		"%2hhx%2hhx%2hhx%2hhx-"
212  		"%2hhx%2hhx-"
213  		"%2hhx%2hhx-"
214  		"%2hhx%2hhx-"
215  		"%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%n",
216  		&uu[0], &uu[1], &uu[2], &uu[3],
217  		&uu[4], &uu[5],
218  		&uu[6], &uu[7],
219  		&uu[8], &uu[9],
220  		&uu[10], &uu[11], &uu[12], &uu[13], &uu[14], &uu[15], &n);
221  
222  	return (n != 36 || in[n] != '\0' ? -1 : 0);
223  }
224  
225  void
226  uuid_unparse_lower(const uuid_t uu, uuid_string_t out)
227  {
228  	snprintf(out,
229  		sizeof(uuid_string_t),
230  		"%02x%02x%02x%02x-"
231  		"%02x%02x-"
232  		"%02x%02x-"
233  		"%02x%02x-"
234  		"%02x%02x%02x%02x%02x%02x",
235  		uu[0], uu[1], uu[2], uu[3],
236  		uu[4], uu[5],
237  		uu[6], uu[7],
238  		uu[8], uu[9],
239  		uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
240  }
241  
242  void
243  uuid_unparse_upper(const uuid_t uu, uuid_string_t out)
244  {
245  	snprintf(out,
246  		sizeof(uuid_string_t),
247  		"%02X%02X%02X%02X-"
248  		"%02X%02X-"
249  		"%02X%02X-"
250  		"%02X%02X-"
251  		"%02X%02X%02X%02X%02X%02X",
252  		uu[0], uu[1], uu[2], uu[3],
253  		uu[4], uu[5],
254  		uu[6], uu[7],
255  		uu[8], uu[9],
256  		uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
257  }
258  
259  void
260  uuid_unparse(const uuid_t uu, uuid_string_t out)
261  {
262  	uuid_unparse_upper(uu, out);
263  }