00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00038 #include "blocxx/BLOCXX_config.h"
00039 #include "blocxx/UUID.hpp"
00040 #include "blocxx/NonRecursiveMutex.hpp"
00041 #include "blocxx/NonRecursiveMutexLock.hpp"
00042 #include "blocxx/Types.hpp"
00043 #include "blocxx/Format.hpp"
00044 #include "blocxx/SecureRand.hpp"
00045 #include "blocxx/ExceptionIds.hpp"
00046
00047 #if !defined(BLOCXX_WIN32)
00048 #include <sys/time.h>
00049 #endif
00050
00051 #ifdef BLOCXX_WIN32
00052 #include <winsock2.h>
00053 #endif
00054
00055 #include <string.h>
00056 #include <stdlib.h>
00057 #include <ctype.h>
00058
00059 namespace BLOCXX_NAMESPACE
00060 {
00061
00062 BLOCXX_DEFINE_EXCEPTION_WITH_ID(UUID);
00063
00064 namespace {
00065
00066 typedef UInt64 uuid_time_t;
00067 struct uuid_node_t
00068 {
00069 unsigned char nodeId[6];
00070 };
00071 struct uuid_state
00072 {
00073 uuid_time_t timestamp;
00074 uuid_node_t nodeId;
00075 UInt16 clockSequence;
00076 };
00077
00078 uuid_state g_state;
00079 NonRecursiveMutex g_guard;
00080
00081 #ifdef BLOCXX_WIN32
00082
00083
00084 static const unsigned __int64 epoch = 116444736000000000L;
00085
00086 int gettimeofday(struct timeval * tp, int bogusParm)
00087 {
00088 FILETIME file_time;
00089 SYSTEMTIME system_time;
00090 ULARGE_INTEGER ularge;
00091
00092 GetSystemTime(&system_time);
00093 SystemTimeToFileTime(&system_time, &file_time);
00094 ularge.LowPart = file_time.dwLowDateTime;
00095 ularge.HighPart = file_time.dwHighDateTime;
00096
00097 tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L);
00098 tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
00099
00100 return 0;
00101 }
00102 #endif
00103
00105 void getSystemTime(uuid_time_t *uuid_time)
00106 {
00107 struct timeval tp;
00108 gettimeofday(&tp, 0);
00109
00110
00111
00112 *uuid_time =
00113 (static_cast<unsigned long long>(tp.tv_sec) * 10000000) +
00114 (tp.tv_usec * 10) +
00115 ((static_cast<unsigned long long>(0x01B21DD2)) << 32) +
00116 0x13814000;
00117 }
00119
00120 uuid_time_t timeLast;
00121 UInt16 uuidsThisTick;
00122 bool currentTimeInited = false;
00123 void getCurrentTime(uuid_time_t * timestamp)
00124 {
00125 uuid_time_t timeNow;
00126 if (!currentTimeInited)
00127 {
00128 getSystemTime(&timeLast);
00129 uuidsThisTick = 0;
00130 currentTimeInited = true;
00131 }
00132 getSystemTime(&timeNow);
00133 if (timeLast != timeNow)
00134 {
00135 uuidsThisTick = 0;
00136 timeLast = timeNow;
00137 }
00138 else
00139 {
00140 uuidsThisTick++;
00141 }
00142
00143 *timestamp = timeNow + uuidsThisTick;
00144 }
00146
00147 unsigned char nodeId[6];
00148 bool nodeIdInitDone = false;
00149 void getNodeIdentifier(uuid_node_t *node)
00150 {
00151
00152
00153
00154 if (!nodeIdInitDone)
00155 {
00156 Secure::rand(nodeId, sizeof(nodeId));
00157
00158 nodeId[0] |= 0x80;
00159 nodeIdInitDone = true;
00160 }
00161 memcpy(node->nodeId, nodeId, sizeof(node->nodeId));
00162 }
00164 inline unsigned char decodeHex(char c)
00165 {
00166 if (isdigit(c))
00167 {
00168 return c - '0';
00169 }
00170 else
00171 {
00172 c = toupper(c);
00173 return c - 'A' + 0xA;
00174 }
00175 }
00177 inline unsigned char fromHexStr(char c1, char c2, const String& uuidStr)
00178 {
00179 if (!isxdigit(c1) || !isxdigit(c2))
00180 {
00181 BLOCXX_THROW(UUIDException, Format("Invalid UUID: %1", uuidStr).c_str());
00182 }
00183 return (decodeHex(c1) << 4) | decodeHex(c2);
00184 }
00186 inline char toHexHi(unsigned char c)
00187 {
00188 unsigned char t = c >> 4;
00189 return t >= 10 ? t - 10 + 'a' : t + '0';
00190 }
00192 inline char toHexLow(unsigned char c)
00193 {
00194 unsigned char t = c & 0xF;
00195 return t >= 10 ? t - 10 + 'a' : t + '0';
00196 }
00197 }
00199 UUID::UUID()
00200 {
00201 NonRecursiveMutexLock l(g_guard);
00202 uuid_time_t timestamp;
00203 getCurrentTime(×tamp);
00204 uuid_node_t node;
00205 getNodeIdentifier(&node);
00206 uuid_time_t last_time = g_state.timestamp;
00207 UInt16 clockseq = g_state.clockSequence;
00208 uuid_node_t last_node = g_state.nodeId;
00209
00210 if (timestamp < last_time)
00211 {
00212 ++clockseq;
00213 }
00214
00215 g_state.timestamp = last_time;
00216 g_state.clockSequence = clockseq;
00217 g_state.nodeId = last_node;
00218 l.release();
00219
00220
00221 UInt32 tmp = static_cast<UInt32>(timestamp & 0xFFFFFFFF);
00222 m_uuid[3] = static_cast<UInt8>(tmp);
00223 tmp >>= 8;
00224 m_uuid[2] = static_cast<UInt8>(tmp);
00225 tmp >>= 8;
00226 m_uuid[1] = static_cast<UInt8>(tmp);
00227 tmp >>= 8;
00228 m_uuid[0] = static_cast<UInt8>(tmp);
00229
00230 tmp = static_cast<UInt16>((timestamp >> 32) & 0xFFFF);
00231 m_uuid[5] = static_cast<UInt8>(tmp);
00232 tmp >>= 8;
00233 m_uuid[4] = static_cast<UInt8>(tmp);
00234
00235 tmp = static_cast<UInt16>(((timestamp >> 48) & 0x0FFF) | (1 << 12));
00236 m_uuid[7] = static_cast<UInt8>(tmp);
00237 tmp >>= 8;
00238 m_uuid[6] = static_cast<UInt8>(tmp);
00239
00240 tmp = clockseq & 0xFF;
00241 m_uuid[9] = static_cast<UInt8>(tmp);
00242
00243 tmp = (clockseq & 0x3F00) >> 8 | 0x80;
00244 m_uuid[8] = static_cast<UInt8>(tmp);
00245 memcpy(m_uuid+10, &node, 6);
00246 }
00248 UUID::UUID(const String& uuidStr)
00249 {
00250 const char* s = uuidStr.c_str();
00251 if (uuidStr.length() != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
00252 {
00253 BLOCXX_THROW(UUIDException, Format("Invalid UUID: %1", uuidStr).c_str());
00254 }
00255 m_uuid[0] = fromHexStr(s[0], s[1], uuidStr);
00256 m_uuid[1] = fromHexStr(s[2], s[3], uuidStr);
00257 m_uuid[2] = fromHexStr(s[4], s[5], uuidStr);
00258 m_uuid[3] = fromHexStr(s[6], s[7], uuidStr);
00259 m_uuid[4] = fromHexStr(s[9], s[10], uuidStr);
00260 m_uuid[5] = fromHexStr(s[11], s[12], uuidStr);
00261 m_uuid[6] = fromHexStr(s[14], s[15], uuidStr);
00262 m_uuid[7] = fromHexStr(s[16], s[17], uuidStr);
00263 m_uuid[8] = fromHexStr(s[19], s[20], uuidStr);
00264 m_uuid[9] = fromHexStr(s[21], s[22], uuidStr);
00265 m_uuid[10] = fromHexStr(s[24], s[25], uuidStr);
00266 m_uuid[11] = fromHexStr(s[26], s[27], uuidStr);
00267 m_uuid[12] = fromHexStr(s[28], s[29], uuidStr);
00268 m_uuid[13] = fromHexStr(s[30], s[31], uuidStr);
00269 m_uuid[14] = fromHexStr(s[32], s[33], uuidStr);
00270 m_uuid[15] = fromHexStr(s[34], s[35], uuidStr);
00271 }
00273 String
00274 UUID::toString() const
00275 {
00276
00277
00278 const size_t uuidlen = 37;
00279 char* buf = new char[uuidlen];
00280 buf[0] = toHexHi(m_uuid[0]); buf[1] = toHexLow(m_uuid[0]);
00281 buf[2] = toHexHi(m_uuid[1]); buf[3] = toHexLow(m_uuid[1]);
00282 buf[4] = toHexHi(m_uuid[2]); buf[5] = toHexLow(m_uuid[2]);
00283 buf[6] = toHexHi(m_uuid[3]); buf[7] = toHexLow(m_uuid[3]);
00284 buf[8] = '-';
00285 buf[9] = toHexHi(m_uuid[4]); buf[10] = toHexLow(m_uuid[4]);
00286 buf[11] = toHexHi(m_uuid[5]); buf[12] = toHexLow(m_uuid[5]);
00287 buf[13] = '-';
00288 buf[14] = toHexHi(m_uuid[6]); buf[15] = toHexLow(m_uuid[6]);
00289 buf[16] = toHexHi(m_uuid[7]); buf[17] = toHexLow(m_uuid[7]);
00290 buf[18] = '-';
00291 buf[19] = toHexHi(m_uuid[8]); buf[20] = toHexLow(m_uuid[8]);
00292 buf[21] = toHexHi(m_uuid[9]); buf[22] = toHexLow(m_uuid[9]);
00293 buf[23] = '-';
00294 buf[24] = toHexHi(m_uuid[10]); buf[25] = toHexLow(m_uuid[10]);
00295 buf[26] = toHexHi(m_uuid[11]); buf[27] = toHexLow(m_uuid[11]);
00296 buf[28] = toHexHi(m_uuid[12]); buf[29] = toHexLow(m_uuid[12]);
00297 buf[30] = toHexHi(m_uuid[13]); buf[31] = toHexLow(m_uuid[13]);
00298 buf[32] = toHexHi(m_uuid[14]); buf[33] = toHexLow(m_uuid[14]);
00299 buf[34] = toHexHi(m_uuid[15]); buf[35] = toHexLow(m_uuid[15]);
00300 buf[36] = '\0';
00301
00302 return String(String::E_TAKE_OWNERSHIP, buf, uuidlen-1);
00303 }
00305 bool operator==(const UUID& x, const UUID& y)
00306 {
00307 return memcmp(x.m_uuid, y.m_uuid, sizeof(x.m_uuid)) == 0;
00308 }
00310 bool operator<(const UUID& x, const UUID& y)
00311 {
00312 return memcmp(x.m_uuid, y.m_uuid, sizeof(x.m_uuid)) < 0;
00313 }
00315 bool operator!=(const UUID& x, const UUID& y)
00316 {
00317 return !(x == y);
00318 }
00319
00320 }
00321