uuid.cpp
Engine/source/core/util/uuid.cpp
Classes:
Namespaces:
namespace
Public Defines
Public Typedefs
Public Functions
int
create_token(uuid_state * st, xuuid_t * u)
create_uuid_state(uuid_state * st)
int
dav_parse_hexpair(const char * s)
format_token(char * target, const xuuid_t * u)
format_uuid_v1(xuuid_t * uuid, unsigned16 clockseq, uuid_time_t timestamp, uuid_node_t node)
get_current_time(uuid_time_t * timestamp)
get_random_info(unsigned char seed)
get_system_time(uuid_time_t * uuid_time)
int
parse_token(const char * char_token, xuuid_t * bin_token)
Detailed Description
Public Defines
I64(C) C##LL
unsigned64_t() unsigned long long
UUIDS_PER_TICK() 1024
Public Typedefs
typedef unsigned short unsigned16
typedef unsigned long unsigned32
typedef unsigned char unsigned8
typedef unsigned64_t uuid_time_t
Public Functions
create_token(uuid_state * st, xuuid_t * u)
create_uuid_state(uuid_state * st)
dav_parse_hexpair(const char * s)
format_token(char * target, const xuuid_t * u)
format_uuid_v1(xuuid_t * uuid, unsigned16 clockseq, uuid_time_t timestamp, uuid_node_t node)
get_current_time(uuid_time_t * timestamp)
get_pseudo_node_identifier(uuid_node_t * node)
get_random_info(unsigned char seed)
get_system_time(uuid_time_t * uuid_time)
parse_token(const char * char_token, xuuid_t * bin_token)
true_random(void )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23// Original code: 24/* 25** Copyright (C) 1998-1999 Greg Stein. All Rights Reserved. 26** 27** By using this file, you agree to the terms and conditions set forth in 28** the LICENSE.html file which can be found at the top level of the mod_dav 29** distribution or at http://www.webdav.org/mod_dav/license-1.html. 30** 31** Contact information: 32** Greg Stein, PO Box 3151, Redmond, WA, 98073 33** gstein@lyra.org, http://www.webdav.org/mod_dav/ 34*/ 35 36/* 37** DAV opaquelocktoken scheme implementation 38** 39** Written 5/99 by Keith Wannamaker, wannamak@us.ibm.com 40** Adapted from ISO/DCE RPC spec and a former Internet Draft 41** by Leach and Salz: 42** http://www.ics.uci.edu/pub/ietf/webdav/uuid-guid/draft-leach-uuids-guids-01 43** 44** Portions of the code are covered by the following license: 45** 46** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. 47** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & 48** Digital Equipment Corporation, Maynard, Mass. 49** Copyright (c) 1998 Microsoft. 50** To anyone who acknowledges that this file is provided "AS IS" 51** without any express or implied warranty: permission to use, copy, 52** modify, and distribute this file for any purpose is hereby 53** granted without fee, provided that the above copyright notices and 54** this notice appears in all source code copies, and that none of 55** the names of Open Software Foundation, Inc., Hewlett-Packard 56** Company, or Digital Equipment Corporation be used in advertising 57** or publicity pertaining to distribution of the software without 58** specific, written prior permission. Neither Open Software 59** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment 60** Corporation makes any representations about the suitability of 61** this software for any purpose. 62*/ 63 64#include "platform/platform.h" 65#include <string.h> 66#include <stdio.h> 67#include <stdlib.h> 68#include <time.h> 69#include <ctype.h> 70 71#include "core/util/md5.h" 72 73#if defined (TORQUE_OS_MAC) && defined(TORQUE_CPU_X64) 74typedef unsigned int unsigned32; 75#else 76typedef unsigned long unsigned32; 77#endif 78typedef unsigned short unsigned16; 79typedef unsigned char unsigned8; 80 81typedef struct { 82 char nodeID[6]; 83} uuid_node_t; 84 85#undef xuuid_t 86 87typedef struct _uuid_t 88{ 89 unsigned32 time_low; 90 unsigned16 time_mid; 91 unsigned16 time_hi_and_version; 92 unsigned8 clock_seq_hi_and_reserved; 93 unsigned8 clock_seq_low; 94 unsigned8 node[6]; 95} xuuid_t; 96 97/* data type for UUID generator persistent state */ 98 99typedef struct { 100 uuid_node_t node; /* saved node ID */ 101 unsigned16 cs; /* saved clock sequence */ 102} uuid_state; 103 104#if defined(_XBOX) 105#include <xtl.h> 106#elif defined(_WIN32) 107#include <windows.h> 108#else 109#include <sys/types.h> 110#include <sys/time.h> 111#include <unistd.h> 112#ifdef XP_BEOS 113#include <be/net/netdb.h> 114#endif 115#endif 116 117/* set the following to the number of 100ns ticks of the actual resolution of 118 your system's clock */ 119#define UUIDS_PER_TICK 1024 120 121/* Set this to what your compiler uses for 64 bit data type */ 122#ifdef _WIN32 123#define unsigned64_t unsigned __int64 124#define I64(C) C 125#else 126#define unsigned64_t unsigned long long 127#define I64(C) C##LL 128#endif 129 130typedef unsigned64_t uuid_time_t; 131 132static void format_uuid_v1(xuuid_t * uuid, unsigned16 clockseq, uuid_time_t timestamp, uuid_node_t node); 133static void get_current_time(uuid_time_t * timestamp); 134static unsigned16 true_random(void); 135static void get_pseudo_node_identifier(uuid_node_t *node); 136static void get_system_time(uuid_time_t *uuid_time); 137static void get_random_info(unsigned char seed[16]); 138 139 140/* dav_create_opaquelocktoken - generates a UUID version 1 token. 141 * Clock_sequence and node_address set to pseudo-random 142 * numbers during init. 143 * 144 * Should postpend pid to account for non-seralized creation? 145 */ 146static int create_token(uuid_state *st, xuuid_t *u) 147{ 148 uuid_time_t timestamp; 149 150 get_current_time(×tamp); 151 format_uuid_v1(u, st->cs, timestamp, st->node); 152 153 return 1; 154} 155 156/* 157 * dav_create_uuid_state - seed UUID state with pseudorandom data 158 */ 159static void create_uuid_state(uuid_state *st) 160{ 161 st->cs = true_random(); 162 get_pseudo_node_identifier(&st->node); 163} 164 165/* 166 * dav_format_opaquelocktoken - generates a text representation 167 * of an opaquelocktoken 168 */ 169static void format_token(char *target, const xuuid_t *u) 170{ 171 sprintf(target, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 172 u->time_low, u->time_mid, u->time_hi_and_version, 173 u->clock_seq_hi_and_reserved, u->clock_seq_low, 174 u->node[0], u->node[1], u->node[2], 175 u->node[3], u->node[4], u->node[5]); 176} 177 178/* convert a pair of hex digits to an integer value [0,255] */ 179static int dav_parse_hexpair(const char *s) 180{ 181 int result; 182 int temp; 183 184 result = s[0] - '0'; 185 if (result > 48) 186 result = (result - 39) << 4; 187 else if (result > 16) 188 result = (result - 7) << 4; 189 else 190 result = result << 4; 191 192 temp = s[1] - '0'; 193 if (temp > 48) 194 result |= temp - 39; 195 else if (temp > 16) 196 result |= temp - 7; 197 else 198 result |= temp; 199 200 return result; 201} 202 203/* dav_parse_locktoken: Parses string produced from 204 * dav_format_opaquelocktoken back into a xuuid_t 205 * structure. On failure, return DAV_IF_ERROR_PARSE, 206 * else DAV_IF_ERROR_NONE. 207 */ 208static int parse_token(const char *char_token, xuuid_t *bin_token) 209{ 210 int i; 211 212 for (i = 0; i < 36; ++i) { 213 char c = char_token[i]; 214 if (!isxdigit(c) && 215 !(c == '-' && (i == 8 || i == 13 || i == 18 || i == 23))) 216 return -1; 217 } 218 if (char_token[36] != '\0') 219 return -1; 220 221 bin_token->time_low = 222 (dav_parse_hexpair(&char_token[0]) << 24) | 223 (dav_parse_hexpair(&char_token[2]) << 16) | 224 (dav_parse_hexpair(&char_token[4]) << 8) | 225 dav_parse_hexpair(&char_token[6]); 226 227 bin_token->time_mid = 228 (dav_parse_hexpair(&char_token[9]) << 8) | 229 dav_parse_hexpair(&char_token[11]); 230 231 bin_token->time_hi_and_version = 232 (dav_parse_hexpair(&char_token[14]) << 8) | 233 dav_parse_hexpair(&char_token[16]); 234 235 bin_token->clock_seq_hi_and_reserved = dav_parse_hexpair(&char_token[19]); 236 bin_token->clock_seq_low = dav_parse_hexpair(&char_token[21]); 237 238 for (i = 6; i--;) 239 bin_token->node[i] = dav_parse_hexpair(&char_token[i*2+24]); 240 241 return 0; 242} 243 244/* format_uuid_v1 -- make a UUID from the timestamp, clockseq, and node ID */ 245static void format_uuid_v1(xuuid_t * uuid, unsigned16 clock_seq, 246 uuid_time_t timestamp, uuid_node_t node) 247{ 248 /* Construct a version 1 uuid with the information we've gathered 249 * plus a few constants. */ 250 uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); 251 uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); 252 uuid->time_hi_and_version = (unsigned short)((timestamp >> 48) & 0x0FFF); 253 uuid->time_hi_and_version |= (1 << 12); 254 uuid->clock_seq_low = clock_seq & 0xFF; 255 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8; 256 uuid->clock_seq_hi_and_reserved |= 0x80; 257 memcpy(&uuid->node, &node, sizeof uuid->node); 258} 259 260/* get-current_time -- get time as 60 bit 100ns ticks since whenever. 261 Compensate for the fact that real clock resolution is less than 100ns. */ 262static void get_current_time(uuid_time_t * timestamp) 263{ 264 uuid_time_t time_now; 265 static uuid_time_t time_last; 266 static unsigned16 uuids_this_tick; 267 static int inited = 0; 268 269 if (!inited) { 270 get_system_time(&time_now); 271 uuids_this_tick = UUIDS_PER_TICK; 272 inited = 1; 273 }; 274 275 while (1) { 276 get_system_time(&time_now); 277 278 /* if clock reading changed since last UUID generated... */ 279 if (time_last != time_now) { 280 /* reset count of uuids gen'd with this clock reading */ 281 uuids_this_tick = 0; 282 break; 283 }; 284 if (uuids_this_tick < UUIDS_PER_TICK) { 285 uuids_this_tick++; 286 break; 287 }; /* going too fast for our clock; spin */ 288 }; /* add the count of uuids to low order bits of the clock reading */ 289 290 *timestamp = time_now + uuids_this_tick; 291 time_last = time_now; 292} 293 294/* true_random -- generate a crypto-quality random number. 295 This sample doesn't do that. */ 296static unsigned16 true_random(void) 297{ 298 uuid_time_t time_now; 299 300 get_system_time(&time_now); 301 time_now = time_now/<a href="/coding/file/uuid_8cpp/#uuid_8cpp_1a3af0a7694d63105350d174f4e9143d55">UUIDS_PER_TICK</a>; 302 srand((unsigned int)(((time_now >> 32) ^ time_now)&0xffffffff)); 303 304 return rand(); 305} 306 307/* This sample implementation generates a random node ID * 308 * in lieu of a system dependent call to get IEEE node ID. */ 309static void get_pseudo_node_identifier(uuid_node_t *node) 310{ 311 unsigned char seed[16]; 312 313 get_random_info(seed); 314 seed[0] |= 0x80; 315 memcpy(node, seed, sizeof(uuid_node_t)); 316} 317 318/* system dependent call to get the current system time. 319 Returned as 100ns ticks since Oct 15, 1582, but resolution may be 320 less than 100ns. */ 321 322#ifdef _WIN32 323 324static void get_system_time(uuid_time_t *uuid_time) 325{ 326 ULARGE_INTEGER time; 327 328 GetSystemTimeAsFileTime((FILETIME *)&time); 329 330 /* NT keeps time in FILETIME format which is 100ns ticks since 331 Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582. 332 The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec) 333 + 18 years and 5 leap days. */ 334 335 time.QuadPart += 336 (unsigned __int64) (1000*1000*10) 337 * (unsigned __int64) (60 * 60 * 24) 338 * (unsigned __int64) (17+30+31+365*18+5); 339 *uuid_time = time.QuadPart; 340} 341 342#if defined(_XBOX) 343#include "platform/platformAssert.h" 344#endif 345 346static void get_random_info(unsigned char seed[16]) 347{ 348#if defined(_XBOX) 349 AssertFatal(false, "get_random_info not implemented on Xbox360"); 350#else 351 MD5_CTX c; 352 struct { 353 MEMORYSTATUS m; 354 SYSTEM_INFO s; 355 FILETIME t; 356 LARGE_INTEGER pc; 357 DWORD tc; 358 DWORD l; 359 TCHAR hostname[MAX_COMPUTERNAME_LENGTH + 1]; 360 361 } r; 362 363 MD5Init(&c); /* memory usage stats */ 364 GlobalMemoryStatus(&r.m); /* random system stats */ 365 GetSystemInfo(&r.s); /* 100ns resolution (nominally) time of day */ 366 GetSystemTimeAsFileTime(&r.t); /* high resolution performance counter */ 367 QueryPerformanceCounter(&r.pc); /* milliseconds since last boot */ 368 r.tc = GetTickCount(); 369 r.l = MAX_COMPUTERNAME_LENGTH + 1; 370 371 GetComputerName(r.hostname, &r.l ); 372 MD5Update(&c, (unsigned char *) &r, sizeof(r)); 373 MD5Final(seed, &c); 374#endif 375} 376 377#else /* WIN32 */ 378 379static void get_system_time(uuid_time_t *uuid_time) 380{ 381 struct timeval tp; 382 383 gettimeofday(&tp, (struct timezone *)0); 384 385 /* Offset between UUID formatted times and Unix formatted times. 386 UUID UTC base time is October 15, 1582. 387 Unix base time is January 1, 1970. */ 388 *uuid_time = (tp.tv_sec * 10000000) + (tp.tv_usec * 10) + 389 I64(0x01B21DD213814000); 390} 391 392static void get_random_info(unsigned char seed[16]) 393{ 394 MD5_CTX c; 395 /* Leech & Salz use Linux-specific struct sysinfo; 396 * replace with pid/tid for portability (in the spirit of mod_unique_id) */ 397 struct { 398 /* Add thread id here, if applicable, when we get to pthread or apr */ 399 pid_t pid; 400 struct timeval t; 401 char hostname[257]; 402 403 } r; 404 405 MD5Init(&c); 406 r.pid = getpid(); 407 gettimeofday(&r.t, (struct timezone *)0); 408 gethostname(r.hostname, 256); 409 MD5Update(&c, (unsigned char *)&r, sizeof(r)); 410 MD5Final(seed, &c); 411} 412 413#endif /* WIN32 */ 414 415#include "core/util/uuid.h" 416 417namespace { 418 bool gUUIDStateInitialized; 419 uuid_state gUUIDState; 420} 421 422namespace Torque 423{ 424 UUID UUID::smNull; 425 426 void UUID::generate() 427 { 428 if( !gUUIDStateInitialized ) 429 { 430 create_uuid_state( &gUUIDState ); 431 gUUIDStateInitialized = true; 432 } 433 434 create_token( &gUUIDState, ( xuuid_t* ) this ); 435 } 436 437 String UUID::toString() const 438 { 439 char buffer[ 1024 ]; 440 format_token( buffer, ( xuuid_t* ) this ); 441 return buffer; 442 } 443 444 bool UUID::fromString( const char* str ) 445 { 446 if( parse_token( str, ( xuuid_t* ) this ) != 0 ) 447 { 448 dMemset( this, 0, sizeof( UUID ) ); 449 return false; 450 } 451 452 return true; 453 } 454 455 U32 UUID::getHash() const 456 { 457 return ( a + b + c + d + e + f[ 0 ] + f[ 1 ] + f[ 2 ] + f[ 3 ] + f[ 4 ] + f[ 5 ] ); 458 } 459} 460
