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#include "console/enginePrimitives.h" 73 74#if defined (TORQUE_OS_MAC) && defined(TORQUE_CPU_X64) 75typedef unsigned int unsigned32; 76#else 77typedef unsigned long unsigned32; 78#endif 79typedef unsigned short unsigned16; 80typedef unsigned char unsigned8; 81 82typedef struct { 83 char nodeID[6]; 84} uuid_node_t; 85 86#undef xuuid_t 87 88typedef struct _uuid_t 89{ 90 unsigned32 time_low; 91 unsigned16 time_mid; 92 unsigned16 time_hi_and_version; 93 unsigned8 clock_seq_hi_and_reserved; 94 unsigned8 clock_seq_low; 95 unsigned8 node[6]; 96} xuuid_t; 97 98/* data type for UUID generator persistent state */ 99 100typedef struct { 101 uuid_node_t node; /* saved node ID */ 102 unsigned16 cs; /* saved clock sequence */ 103} uuid_state; 104 105#if defined(_WIN32) 106#include <windows.h> 107#else 108#include <sys/types.h> 109#include <sys/time.h> 110#include <unistd.h> 111#endif 112 113/* set the following to the number of 100ns ticks of the actual resolution of 114 your system's clock */ 115#define UUIDS_PER_TICK 1024 116 117/* Set this to what your compiler uses for 64 bit data type */ 118#ifdef _WIN32 119#define unsigned64_t unsigned __int64 120#define I64(C) C 121#else 122#define unsigned64_t unsigned long long 123#define I64(C) C##LL 124#endif 125 126typedef unsigned64_t uuid_time_t; 127 128static void format_uuid_v1(xuuid_t * uuid, unsigned16 clockseq, uuid_time_t timestamp, uuid_node_t node); 129static void get_current_time(uuid_time_t * timestamp); 130static unsigned16 true_random(void); 131static void get_pseudo_node_identifier(uuid_node_t *node); 132static void get_system_time(uuid_time_t *uuid_time); 133static void get_random_info(unsigned char seed[16]); 134 135 136/* dav_create_opaquelocktoken - generates a UUID version 1 token. 137 * Clock_sequence and node_address set to pseudo-random 138 * numbers during init. 139 * 140 * Should postpend pid to account for non-seralized creation? 141 */ 142static int create_token(uuid_state *st, xuuid_t *u) 143{ 144 uuid_time_t timestamp; 145 146 get_current_time(×tamp); 147 format_uuid_v1(u, st->cs, timestamp, st->node); 148 149 return 1; 150} 151 152/* 153 * dav_create_uuid_state - seed UUID state with pseudorandom data 154 */ 155static void create_uuid_state(uuid_state *st) 156{ 157 st->cs = true_random(); 158 get_pseudo_node_identifier(&st->node); 159} 160 161/* 162 * dav_format_opaquelocktoken - generates a text representation 163 * of an opaquelocktoken 164 */ 165static void format_token(char *target, const xuuid_t *u) 166{ 167 sprintf(target, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 168 u->time_low, u->time_mid, u->time_hi_and_version, 169 u->clock_seq_hi_and_reserved, u->clock_seq_low, 170 u->node[0], u->node[1], u->node[2], 171 u->node[3], u->node[4], u->node[5]); 172} 173 174/* convert a pair of hex digits to an integer value [0,255] */ 175static int dav_parse_hexpair(const char *s) 176{ 177 int result; 178 int temp; 179 180 result = s[0] - '0'; 181 if (result > 48) 182 result = (result - 39) << 4; 183 else if (result > 16) 184 result = (result - 7) << 4; 185 else 186 result = result << 4; 187 188 temp = s[1] - '0'; 189 if (temp > 48) 190 result |= temp - 39; 191 else if (temp > 16) 192 result |= temp - 7; 193 else 194 result |= temp; 195 196 return result; 197} 198 199/* dav_parse_locktoken: Parses string produced from 200 * dav_format_opaquelocktoken back into a xuuid_t 201 * structure. On failure, return DAV_IF_ERROR_PARSE, 202 * else DAV_IF_ERROR_NONE. 203 */ 204static int parse_token(const char *char_token, xuuid_t *bin_token) 205{ 206 int i; 207 208 for (i = 0; i < 36; ++i) { 209 char c = char_token[i]; 210 if (!isxdigit(c) && 211 !(c == '-' && (i == 8 || i == 13 || i == 18 || i == 23))) 212 return -1; 213 } 214 if (char_token[36] != '\0') 215 return -1; 216 217 bin_token->time_low = 218 (dav_parse_hexpair(&char_token[0]) << 24) | 219 (dav_parse_hexpair(&char_token[2]) << 16) | 220 (dav_parse_hexpair(&char_token[4]) << 8) | 221 dav_parse_hexpair(&char_token[6]); 222 223 bin_token->time_mid = 224 (dav_parse_hexpair(&char_token[9]) << 8) | 225 dav_parse_hexpair(&char_token[11]); 226 227 bin_token->time_hi_and_version = 228 (dav_parse_hexpair(&char_token[14]) << 8) | 229 dav_parse_hexpair(&char_token[16]); 230 231 bin_token->clock_seq_hi_and_reserved = dav_parse_hexpair(&char_token[19]); 232 bin_token->clock_seq_low = dav_parse_hexpair(&char_token[21]); 233 234 for (i = 6; i--;) 235 bin_token->node[i] = dav_parse_hexpair(&char_token[i*2+24]); 236 237 return 0; 238} 239 240/* format_uuid_v1 -- make a UUID from the timestamp, clockseq, and node ID */ 241static void format_uuid_v1(xuuid_t * uuid, unsigned16 clock_seq, 242 uuid_time_t timestamp, uuid_node_t node) 243{ 244 /* Construct a version 1 uuid with the information we've gathered 245 * plus a few constants. */ 246 uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); 247 uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); 248 uuid->time_hi_and_version = (unsigned short)((timestamp >> 48) & 0x0FFF); 249 uuid->time_hi_and_version |= (1 << 12); 250 uuid->clock_seq_low = clock_seq & 0xFF; 251 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8; 252 uuid->clock_seq_hi_and_reserved |= 0x80; 253 memcpy(&uuid->node, &node, sizeof uuid->node); 254} 255 256/* get-current_time -- get time as 60 bit 100ns ticks since whenever. 257 Compensate for the fact that real clock resolution is less than 100ns. */ 258static void get_current_time(uuid_time_t * timestamp) 259{ 260 uuid_time_t time_now; 261 static uuid_time_t time_last; 262 static unsigned16 uuids_this_tick; 263 static int inited = 0; 264 265 if (!inited) { 266 get_system_time(&time_now); 267 uuids_this_tick = UUIDS_PER_TICK; 268 inited = 1; 269 }; 270 271 while (1) { 272 get_system_time(&time_now); 273 274 /* if clock reading changed since last UUID generated... */ 275 if (time_last != time_now) { 276 /* reset count of uuids gen'd with this clock reading */ 277 uuids_this_tick = 0; 278 break; 279 }; 280 if (uuids_this_tick < UUIDS_PER_TICK) { 281 uuids_this_tick++; 282 break; 283 }; /* going too fast for our clock; spin */ 284 }; /* add the count of uuids to low order bits of the clock reading */ 285 286 *timestamp = time_now + uuids_this_tick; 287 time_last = time_now; 288} 289 290/* true_random -- generate a crypto-quality random number. 291 This sample doesn't do that. */ 292static unsigned16 true_random(void) 293{ 294 uuid_time_t time_now; 295 296 get_system_time(&time_now); 297 time_now = time_now/<a href="/coding/file/uuid_8cpp/#uuid_8cpp_1a3af0a7694d63105350d174f4e9143d55">UUIDS_PER_TICK</a>; 298 srand((unsigned int)(((time_now >> 32) ^ time_now)&0xffffffff)); 299 300 return rand(); 301} 302 303/* This sample implementation generates a random node ID * 304 * in lieu of a system dependent call to get IEEE node ID. */ 305static void get_pseudo_node_identifier(uuid_node_t *node) 306{ 307 unsigned char seed[16]; 308 309 get_random_info(seed); 310 seed[0] |= 0x80; 311 memcpy(node, seed, sizeof(uuid_node_t)); 312} 313 314/* system dependent call to get the current system time. 315 Returned as 100ns ticks since Oct 15, 1582, but resolution may be 316 less than 100ns. */ 317 318#ifdef _WIN32 319 320static void get_system_time(uuid_time_t *uuid_time) 321{ 322 ULARGE_INTEGER time; 323 324 GetSystemTimeAsFileTime((FILETIME *)&time); 325 326 /* NT keeps time in FILETIME format which is 100ns ticks since 327 Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582. 328 The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec) 329 + 18 years and 5 leap days. */ 330 331 time.QuadPart += 332 (unsigned __int64) (1000*1000*10) 333 * (unsigned __int64) (60 * 60 * 24) 334 * (unsigned __int64) (17+30+31+365*18+5); 335 *uuid_time = time.QuadPart; 336} 337 338#if defined(_XBOX) 339#include "platform/platformAssert.h" 340#endif 341 342static void get_random_info(unsigned char seed[16]) 343{ 344#if defined(_XBOX) 345 AssertFatal(false, "get_random_info not implemented on Xbox360"); 346#else 347 MD5_CTX c; 348 struct { 349 MEMORYSTATUS m; 350 SYSTEM_INFO s; 351 FILETIME t; 352 LARGE_INTEGER pc; 353 DWORD tc; 354 DWORD l; 355 TCHAR hostname[MAX_COMPUTERNAME_LENGTH + 1]; 356 357 } r; 358 359 MD5Init(&c); /* memory usage stats */ 360 GlobalMemoryStatus(&r.m); /* random system stats */ 361 GetSystemInfo(&r.s); /* 100ns resolution (nominally) time of day */ 362 GetSystemTimeAsFileTime(&r.t); /* high resolution performance counter */ 363 QueryPerformanceCounter(&r.pc); /* milliseconds since last boot */ 364 r.tc = GetTickCount(); 365 r.l = MAX_COMPUTERNAME_LENGTH + 1; 366 367 GetComputerName(r.hostname, &r.l ); 368 MD5Update(&c, (unsigned char *) &r, sizeof(r)); 369 MD5Final(seed, &c); 370#endif 371} 372 373#else /* WIN32 */ 374 375static void get_system_time(uuid_time_t *uuid_time) 376{ 377 struct timeval tp; 378 379 gettimeofday(&tp, (struct timezone *)0); 380 381 /* Offset between UUID formatted times and Unix formatted times. 382 UUID UTC base time is October 15, 1582. 383 Unix base time is January 1, 1970. */ 384 *uuid_time = (tp.tv_sec * 10000000) + (tp.tv_usec * 10) + 385 I64(0x01B21DD213814000); 386} 387 388static void get_random_info(unsigned char seed[16]) 389{ 390 MD5_CTX c; 391 /* Leech & Salz use Linux-specific struct sysinfo; 392 * replace with pid/tid for portability (in the spirit of mod_unique_id) */ 393 struct { 394 /* Add thread id here, if applicable, when we get to pthread or apr */ 395 pid_t pid; 396 struct timeval t; 397 char hostname[257]; 398 399 } r; 400 401 MD5Init(&c); 402 r.pid = getpid(); 403 gettimeofday(&r.t, (struct timezone *)0); 404 gethostname(r.hostname, 256); 405 MD5Update(&c, (unsigned char *)&r, sizeof(r)); 406 MD5Final(seed, &c); 407} 408 409#endif /* WIN32 */ 410 411#include "core/util/uuid.h" 412 413namespace { 414 bool gUUIDStateInitialized; 415 uuid_state gUUIDState; 416} 417 418namespace Torque 419{ 420 UUID UUID::smNull; 421 422 void UUID::generate() 423 { 424 if( !gUUIDStateInitialized ) 425 { 426 create_uuid_state( &gUUIDState ); 427 gUUIDStateInitialized = true; 428 } 429 430 create_token( &gUUIDState, ( xuuid_t* ) this ); 431 } 432 433 String UUID::toString() const 434 { 435 char buffer[ 1024 ]; 436 format_token( buffer, ( xuuid_t* ) this ); 437 return buffer; 438 } 439 440 bool UUID::fromString( const char* str ) 441 { 442 if( parse_token( str, ( xuuid_t* ) this ) != 0 ) 443 { 444 dMemset( this, 0, sizeof( UUID ) ); 445 return false; 446 } 447 448 return true; 449 } 450 451 U32 UUID::getHash() const 452 { 453 return ( a + b + c + d + e + f[ 0 ] + f[ 1 ] + f[ 2 ] + f[ 3 ] + f[ 4 ] + f[ 5 ] ); 454 } 455} 456 457EngineFieldTable::Field Torque::UUIDEngineExport::getAField() 458{ 459 typedef UUID ThisType; 460 return _FIELD(a, a, 1, ""); 461} 462 463EngineFieldTable::Field Torque::UUIDEngineExport::getBField() 464{ 465 typedef UUID ThisType; 466 return _FIELD(b, b, 1, ""); 467} 468 469EngineFieldTable::Field Torque::UUIDEngineExport::getCField() 470{ 471 typedef UUID ThisType; 472 return _FIELD(c, c, 1, ""); 473} 474 475EngineFieldTable::Field Torque::UUIDEngineExport::getDField() 476{ 477 typedef UUID ThisType; 478 return _FIELD(d, d, 1, ""); 479} 480 481EngineFieldTable::Field Torque::UUIDEngineExport::getEField() 482{ 483 typedef UUID ThisType; 484 return _FIELD(e, e, 1, ""); 485} 486 487EngineFieldTable::Field Torque::UUIDEngineExport::getFField() 488{ 489 typedef UUID ThisType; 490 return _FIELD_AS(U8, f, f, 6, ""); 491} 492 493 494 495