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