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