2
0

getuuid.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
  2. * applicable.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * This attempts to generate V1 UUIDs according to the Internet Draft
  18. * located at http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
  19. */
  20. #include "apr.h"
  21. #include "apr_uuid.h"
  22. #include "apr_general.h"
  23. #include "apr_portable.h"
  24. #if !APR_HAS_RANDOM
  25. #include "apr_md5.h"
  26. #endif
  27. #if APR_HAVE_UNISTD_H
  28. #include <unistd.h> /* for getpid, gethostname */
  29. #endif
  30. #if APR_HAVE_STDLIB_H
  31. #include <stdlib.h> /* for rand, srand */
  32. #endif
  33. #if APR_HAVE_STRING_H
  34. #include <string.h>
  35. #endif
  36. #if APR_HAVE_STRINGS_H
  37. #include <strings.h>
  38. #endif
  39. #if APR_HAVE_NETDB_H
  40. #include <netdb.h>
  41. #endif
  42. #if APR_HAVE_SYS_TIME_H
  43. #include <sys/time.h> /* for gettimeofday */
  44. #endif
  45. #define NODE_LENGTH 6
  46. static int uuid_state_seqnum;
  47. static unsigned char uuid_state_node[NODE_LENGTH] = { 0 };
  48. static void get_random_info(unsigned char node[NODE_LENGTH])
  49. {
  50. #if APR_HAS_RANDOM
  51. (void) apr_generate_random_bytes(node, NODE_LENGTH);
  52. #else
  53. unsigned char seed[APR_MD5_DIGESTSIZE];
  54. apr_md5_ctx_t c;
  55. /* ### probably should revise some of this to be a bit more portable */
  56. /* Leach & Salz use Linux-specific struct sysinfo;
  57. * replace with pid/tid for portability (in the spirit of mod_unique_id) */
  58. struct {
  59. /* Add thread id here, if applicable, when we get to pthread or apr */
  60. pid_t pid;
  61. #ifdef NETWARE
  62. apr_uint64_t t;
  63. #else
  64. struct timeval t;
  65. #endif
  66. char hostname[257];
  67. } r;
  68. apr_md5_init(&c);
  69. #ifdef NETWARE
  70. r.pid = NXThreadGetId();
  71. NXGetTime(NX_SINCE_BOOT, NX_USECONDS, &(r.t));
  72. #else
  73. r.pid = getpid();
  74. gettimeofday(&r.t, (struct timezone *)0);
  75. #endif
  76. gethostname(r.hostname, 256);
  77. apr_md5_update(&c, (const unsigned char *)&r, sizeof(r));
  78. apr_md5_final(seed, &c);
  79. memcpy(node, seed, NODE_LENGTH); /* use a subset of the seed bytes */
  80. #endif
  81. }
  82. /* This implementation generates a random node ID instead of a
  83. system-dependent call to get IEEE node ID. This is also more secure:
  84. we aren't passing out our MAC address.
  85. */
  86. static void get_pseudo_node_identifier(unsigned char *node)
  87. {
  88. get_random_info(node);
  89. node[0] |= 0x01; /* this designates a random node ID */
  90. }
  91. static void get_system_time(apr_uint64_t *uuid_time)
  92. {
  93. /* ### fix this call to be more portable? */
  94. *uuid_time = apr_time_now();
  95. /* Offset between UUID formatted times and Unix formatted times.
  96. UUID UTC base time is October 15, 1582.
  97. Unix base time is January 1, 1970. */
  98. *uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000);
  99. }
  100. /* true_random -- generate a crypto-quality random number. */
  101. static int true_random(void)
  102. {
  103. apr_uint64_t time_now;
  104. #if APR_HAS_RANDOM
  105. unsigned char buf[2];
  106. if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) {
  107. return (buf[0] << 8) | buf[1];
  108. }
  109. #endif
  110. /* crap. this isn't crypto quality, but it will be Good Enough */
  111. get_system_time(&time_now);
  112. srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff));
  113. return rand() & 0x0FFFF;
  114. }
  115. static void init_state(void)
  116. {
  117. uuid_state_seqnum = true_random();
  118. get_pseudo_node_identifier(uuid_state_node);
  119. }
  120. static void get_current_time(apr_uint64_t *timestamp)
  121. {
  122. /* ### this needs to be made thread-safe! */
  123. apr_uint64_t time_now;
  124. static apr_uint64_t time_last = 0;
  125. static apr_uint64_t fudge = 0;
  126. get_system_time(&time_now);
  127. /* if clock reading changed since last UUID generated... */
  128. if (time_last != time_now) {
  129. /* The clock reading has changed since the last UUID was generated.
  130. Reset the fudge factor. if we are generating them too fast, then
  131. the fudge may need to be reset to something greater than zero. */
  132. if (time_last + fudge > time_now)
  133. fudge = time_last + fudge - time_now + 1;
  134. else
  135. fudge = 0;
  136. time_last = time_now;
  137. }
  138. else {
  139. /* We generated two really fast. Bump the fudge factor. */
  140. ++fudge;
  141. }
  142. *timestamp = time_now + fudge;
  143. }
  144. APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid)
  145. {
  146. apr_uint64_t timestamp;
  147. unsigned char *d = uuid->data;
  148. #if APR_HAS_OS_UUID
  149. if (apr_os_uuid_get(d) == APR_SUCCESS) {
  150. return;
  151. }
  152. #endif /* !APR_HAS_OS_UUID */
  153. if (!uuid_state_node[0])
  154. init_state();
  155. get_current_time(&timestamp);
  156. /* time_low, uint32 */
  157. d[3] = (unsigned char)timestamp;
  158. d[2] = (unsigned char)(timestamp >> 8);
  159. d[1] = (unsigned char)(timestamp >> 16);
  160. d[0] = (unsigned char)(timestamp >> 24);
  161. /* time_mid, uint16 */
  162. d[5] = (unsigned char)(timestamp >> 32);
  163. d[4] = (unsigned char)(timestamp >> 40);
  164. /* time_hi_and_version, uint16 */
  165. d[7] = (unsigned char)(timestamp >> 48);
  166. d[6] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x10);
  167. /* clock_seq_hi_and_reserved, uint8 */
  168. d[8] = (unsigned char)(((++uuid_state_seqnum >> 8) & 0x3F) | 0x80);
  169. /* clock_seq_low, uint8 */
  170. d[9] = (unsigned char)uuid_state_seqnum;
  171. /* node, byte[6] */
  172. memcpy(&d[10], uuid_state_node, NODE_LENGTH);
  173. }