OW_UUID.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2003-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
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> // for gettimeofday
00046 #endif
00047 
00048 #include <string.h> // for memcmp
00049 #include <stdlib.h> // for rand
00050 #include <ctype.h> // for isxdigit
00051 
00052 namespace OW_NAMESPACE
00053 {
00054 
00055 OW_DEFINE_EXCEPTION_WITH_ID(UUID);
00056 
00057 namespace {
00058 // typedefs
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 // static generator state
00071 uuid_state g_state;
00072 NonRecursiveMutex g_guard;
00073 
00074 #ifdef OW_WIN32
00075 
00076 // FILETIME of Jan 1 1970 00:00:00.
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    // Offset between UUID formatted times and Unix formatted times.
00103    // UUID UTC base time is October 15, 1582.
00104    // Unix base time is January 1, 1970.
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 // these globals are protected by the mutex locked in UUID::UUID()
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    // add the count of uuids to low order bits of the clock reading
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 // these globals are protected by the mutex locked in UUID::UUID()
00150 unsigned char nodeId[6];
00151 bool nodeIdInitDone = false;
00152 void getNodeIdentifier(uuid_node_t *node) 
00153 {
00154    // If we ever get a portable (or ported) method of acquiring the MAC
00155    // address, we should use that.  Until then, we'll just use random
00156    // numbers.
00157    if (!nodeIdInitDone)
00158    {
00159       getRandomBytes(nodeId, sizeof(nodeId));
00160       // Set multicast bit, to prevent conflicts with MAC addressses.
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 } // end anonymous namespace 
00202 UUID::UUID()
00203 {
00204    NonRecursiveMutexLock l(g_guard);
00205    uuid_time_t timestamp;
00206    getCurrentTime(&timestamp);
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    // If clock went backwards (can happen if system clock resolution is low), change clockseq
00213    if (timestamp < last_time)
00214    {
00215       ++clockseq;
00216    }
00217    // save the state for next time
00218    g_state.timestamp = last_time;
00219    g_state.clockSequence = clockseq;
00220    g_state.nodeId = last_node;
00221    l.release();
00222    // stuff fields into the UUID
00223    // do time_low 
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    // do time_mid
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    // do time_hi_and_version
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    // do clk_seq_low
00243    tmp = clockseq & 0xFF;
00244    m_uuid[9] = static_cast<UInt8>(tmp);
00245    // do clk_seq_hi_res
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    // This will return a string like this: 
00280    // 6ba7b810-9dad-11d1-80b4-00c04fd430c8
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 } // end namespace OW_NAMESPACE
00324 

Generated on Thu Feb 9 08:48:17 2006 for openwbem by  doxygen 1.4.6