uuid.cpp 14 KB

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