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 }