00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <config.h>
00019 #include "midgard/uuid.h"
00020 #include "md5.h"
00021 #include <string.h>
00022
00023 gboolean midgard_is_uuid(const gchar *uuid) {
00024 g_assert(uuid != NULL);
00025 static const char format[] = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
00026 int i;
00027 for (i = 0; i < sizeof(format); i++) {
00028 if (format[i] == 'x') {
00029 if (!g_ascii_isxdigit(uuid[i])) {
00030 return FALSE;
00031 }
00032 } else if (uuid[i] != format[i]) {
00033 return FALSE;
00034 }
00035 }
00036 return TRUE;
00037 }
00038
00045 G_LOCK_DEFINE_STATIC(uuid);
00046
00047 gchar *midgard_uuid_new(void) {
00048 static gboolean initialized = FALSE;
00049 static guint64 timestamp;
00050 static guint32 advance;
00051 static guint16 clockseq;
00052 static guint16 node_high;
00053 static guint32 node_low;
00054 guint64 time;
00055 guint16 nowseq;
00056 GTimeVal tv;
00057
00058 G_LOCK(uuid);
00059 g_get_current_time(&tv);
00060 time = ((guint64) tv.tv_sec) * G_USEC_PER_SEC + ((guint64) tv.tv_usec);
00061 time = time * 10 + G_GINT64_CONSTANT(0x01B21DD213814000U);
00062 if (!initialized) {
00063 timestamp = time;
00064 advance = 0;
00065 GRand *rand = g_rand_new();
00066 guint32 r = g_rand_int(rand);
00067 clockseq = r >> 16;
00068 node_high = r | 0x0100;
00069 node_low = g_rand_int(rand);
00070 g_rand_free(rand);
00071 initialized = TRUE;
00072 } else if (time < timestamp) {
00073 timestamp = time;
00074 advance = 0;
00075 clockseq++;
00076 } else if (time == timestamp) {
00077 advance++;
00078 time += advance;
00079 } else {
00080 timestamp = time;
00081 advance = 0;
00082 }
00083 nowseq = clockseq;
00084 G_UNLOCK(uuid);
00085
00086 return g_strdup_printf(
00087 "%08lx-%04x-%04x-%04x-%04x%08lx",
00088 (unsigned long) time,
00089 (unsigned int) (time >> 32) & 0xffff,
00090 (unsigned int) ((time >> 48) & 0x0ffff) | 0x1000,
00091 (unsigned int) (nowseq & 0x3fff) | 0x8000,
00092 (unsigned int) node_high,
00093 (unsigned long) node_low);
00094 }
00095
00102 static const unsigned char namespace_uuid[] = {
00103 0x00, 0xdc, 0x46, 0xa0, 0x0e, 0x0c, 0x10, 0x85,
00104 0x82, 0xbb, 0x00, 0x02, 0xa5, 0xd5, 0xfd, 0x2e
00105 };
00106
00107 gchar *midgard_uuid_external(const gchar *external) {
00108 g_assert(external != NULL);
00109 unsigned char uuid[16];
00110
00111 MD5_CTX md5;
00112 MD5Init(&md5);
00113 MD5Update(&md5, namespace_uuid, sizeof(namespace_uuid));
00114 MD5Update(&md5, (unsigned char *) external, strlen(external));
00115 MD5Final(uuid, &md5);
00116
00117 return g_strdup_printf(
00118 "%08lx-%04x-%04x-%04x-%04x%08lx",
00119 (unsigned long) uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3],
00120 (unsigned int) uuid[4] << 8 | uuid[5],
00121 (unsigned int) ((uuid[6] & 0x0f) | 0x30) << 8 | uuid[7],
00122 (unsigned int) ((uuid[8] & 0x3f) | 0x80) << 8 | uuid[9],
00123 (unsigned int) uuid[10] << 8 | uuid[11],
00124 (unsigned long) uuid[12] << 24 | uuid[13] << 16 | uuid[14] << 8 | uuid[15]);
00125 }