uuid.cpp

Engine/source/core/util/uuid.cpp

More...

Classes:

Namespaces:

namespace

Public Defines

define
I64(C) C##LL
define
unsigned64_t() unsigned long long
define

Public Typedefs

unsigned short
unsigned16 
unsigned long
unsigned32 
unsigned char
unsigned8 
uuid_time_t 

Public Functions

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(&timestamp);
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