Uuid.cxx

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002  
00003     Copyright (c) 2004 Media Development Loan Fund
00004   
00005     This file is part of the Campcaster project.
00006     https://www.campware.org/
00007     To report bugs, send an e-mail to [email protected]
00008   
00009     Campcaster is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013    
00014     Campcaster is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU General Public License for more details.
00018   
00019     You should have received a copy of the GNU General Public License
00020     along with Campcaster; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022   
00023   
00024     Author   : $Author: fgerlits $
00025     Version  : $Revision: 2329 $
00026     Location : $URL: svn://code.campware.org/campcaster/trunk/campcaster/src/modules/core/src/Uuid.cxx $
00027  
00028 ------------------------------------------------------------------------------*/
00029 
00030 /* ============================================================ include files */
00031 
00032 #ifdef HAVE_CONFIG_H
00033  #include "configure.h"
00034 #endif
00035  
00036 #ifdef HAVE_SYS_TIME_H
00037  #include <sys/time.h>
00038 #else
00039  #error need sys/time.h
00040  #endif
00041  
00042 #ifdef HAVE_UNISTD_H
00043  #include <unistd.h>
00044 #else
00045  #error need unistd.h
00046  #endif
00047  
00048 
00049 #include <cstdlib>
00050 #include <iomanip>
00051 #include <sstream>
00052 
00053 #include "LiveSupport/Core/Uuid.h"
00054 
00055 
00056 using namespace LiveSupport::Core;
00057 
00058 /* ===================================================  local data structures */
00059 
00060 
00061 /* ================================================  local constants & macros */
00062 
00063 /*------------------------------------------------------------------------------
00064  *  Set the following to the number of 100ns ticks of the actual
00065  *  resolution of your system's clock
00066  *----------------------------------------------------------------------------*/
00067 #define UUIDS_PER_TICK 1024
00068  
00069 
00070 /* ===============================================  local function prototypes */
00071 
00072 
00073 /* =============================================================  module code */
00074 
00075 /*------------------------------------------------------------------------------
00076  *  Generate a globally unique id.
00077  *----------------------------------------------------------------------------*/
00078 Ptr<Uuid>::Ref
00079 Uuid :: generateId(void)                        throw ()
00080 {
00081     Ptr<Uuid>::Ref  id(new Uuid());
00082 
00083     UuidTime    timestamp;
00084     UuidTime    lastTime;
00085     uint16_t    clockseq;
00086     UuidNode    node;
00087     UuidNode    lastNode;
00088     int         f;
00089 
00090     /* acquire system wide lock so we're alone */
00091     //LOCK;
00092 
00093     /* get current time */
00094     getCurrentTime(×tamp);
00095 
00096     /* get node ID */
00097     getIeeeNodeIdentifier(&node);
00098 
00099     /* get saved state from NV storage */
00100     f = id->readState(&clockseq, &lastTime, &lastNode);
00101 
00102     /* if no NV state, or if clock went backwards, or node ID changed
00103        (e.g., net card swap) change clockseq */
00104     if (!f || memcmp(&node, &lastNode, sizeof(UuidNode))) {
00105         clockseq = trueRandom();
00106     } else if (timestamp < lastTime) {
00107         clockseq++;
00108     }
00109 
00110     /* stuff fields into the UUID */
00111     id->format(clockseq, timestamp, node);
00112     id->representAsString();
00113 
00114     /* save the state for next time */
00115     id->writeState(clockseq, timestamp, node);
00116 
00117     //UNLOCK;
00118 
00119     return id;
00120 }
00121 
00122 
00123 /*------------------------------------------------------------------------------
00124  *  Format the UUID
00125  *----------------------------------------------------------------------------*/
00126 void
00127 Uuid :: format(uint16_t     clockSeq,
00128                UuidTime     timestamp,
00129                UuidNode     node)                               throw ()
00130 {
00131     /* Construct a version 1 uuid with the information we've gathered
00132      * plus a few constants. */
00133     timeLow                = (unsigned long)(timestamp & 0xFFFFFFFF);
00134     timeMid                = (unsigned short)((timestamp >> 32) & 0xFFFF);
00135     timeHiAndVersion       = (unsigned short)((timestamp >> 48) & 0x0FFF);
00136     timeHiAndVersion      |= (1 << 12);
00137     clockSeqLow            = clockSeq & 0xFF;
00138     clockSeqHiAndReserved  = (clockSeq & 0x3F00) >> 8;
00139     clockSeqHiAndReserved |= 0x80;
00140 
00141     for (int i = 0; i < 6; ++i) {
00142         this->node[i] = node.nodeId[i];
00143     }
00144 }
00145 
00146 
00147 /*------------------------------------------------------------------------------
00148  *  Create a string representation of the UUID
00149  *----------------------------------------------------------------------------*/
00150 void
00151 Uuid :: representAsString(void)                                 throw ()
00152 {
00153     std::stringstream  sstr;
00154 
00155     sstr << std::hex << std::setw(8) << std::setfill('0') << timeLow << '-'
00156          << std::hex << std::setw(4) << std::setfill('0') << timeMid << '-'
00157          << std::hex << std::setw(4) << std::setfill('0')
00158                      << timeHiAndVersion << '-'
00159          << std::hex << std::setw(2) << std::setfill('0') 
00160                      << (unsigned short) clockSeqHiAndReserved << '-'
00161          << std::hex << std::setw(2) << std::setfill('0') 
00162                      << (unsigned short) clockSeqLow << '-';
00163     for (int i = 0; i < 6; ++i) {
00164         sstr << std::hex << std::setw(2) << std::setfill('0')
00165              << (unsigned short) this->node[i];
00166     }
00167 
00168     idAsString = sstr.str();
00169 }
00170 
00171 
00172 /*------------------------------------------------------------------------------
00173  *  Read the current state from non-volatile storage
00174  *----------------------------------------------------------------------------*/
00175 int
00176 Uuid :: readState(uint16_t    * clockSeq,
00177                   UuidTime    * timestamp,
00178                   UuidNode    * node)                           throw ()
00179 {
00180     // TODO: read the state from non-volatile storage
00181 
00182     return 0;
00183 }
00184 
00185 
00186 /*------------------------------------------------------------------------------
00187  *  Write the current state to non-volatile storage
00188  *----------------------------------------------------------------------------*/
00189 void
00190 Uuid :: writeState(uint16_t     clockSeq,
00191                    UuidTime     timestamp,
00192                    UuidNode     node)                       throw ()
00193 {
00194     // TODO: write the current state to non-volatile storage
00195 }
00196 
00197 
00198 /*------------------------------------------------------------------------------
00199  *  Get the current time into a timestamp
00200  *----------------------------------------------------------------------------*/
00201 void
00202 Uuid :: getCurrentTime(UuidTime  *timestamp)                throw ()
00203 {
00204     UuidTime             timeNow;
00205     static UuidTime      timeLast;
00206     static uint16_t      uuidsThisTick;
00207     static bool          inited = false;
00208 
00209     if (!inited) {
00210         getSystemTime(&timeNow);
00211         uuidsThisTick = UUIDS_PER_TICK;
00212         inited = true;
00213     };
00214 
00215     while (true) {
00216         getSystemTime(&timeNow);
00217 
00218         /* if clock reading changed since last UUID generated... */
00219         if (timeLast != timeNow) {
00220             /* reset count of uuids gen'd with this clock reading */
00221             uuidsThisTick = 0;
00222             break;
00223         };
00224         if (uuidsThisTick < UUIDS_PER_TICK) {
00225             uuidsThisTick++;
00226             break;
00227         };
00228         /* going too fast for our clock; spin */
00229     };
00230 
00231     /* add the count of uuids to low order bits of the clock reading */
00232     *timestamp = timeNow + uuidsThisTick;
00233 }
00234 
00235 
00236 /*------------------------------------------------------------------------------
00237  *  Get the system time in the UUID UTC base time, which is October 15, 1582
00238  *----------------------------------------------------------------------------*/
00239 void
00240 Uuid :: getSystemTime(UuidTime * uuidTime)                      throw ()
00241 {
00242     struct timeval tp;
00243 
00244     gettimeofday(&tp, (struct timezone *)0);
00245 
00246     /* Offset between UUID formatted times and Unix formatted times.
00247        UUID UTC base time is October 15, 1582.
00248        Unix base time is January 1, 1970.
00249     */
00250     *uuidTime = (tp.tv_sec * 10000000)
00251               + (tp.tv_usec * 10)
00252               + 0x01B21DD213814000LL;
00253 }
00254 
00255 
00256 /*------------------------------------------------------------------------------
00257  *  Get the IEEE node identifier
00258  *----------------------------------------------------------------------------*/
00259 void
00260 Uuid :: getIeeeNodeIdentifier(UuidNode    * node)           throw ()
00261 {
00262     long    hostId = gethostid();
00263 
00264     node->nodeId[5] = (char) (hostId & 0x0000000000ffL);
00265     node->nodeId[4] = (char) ((hostId & 0x00000000ff00L) >> 8);
00266     node->nodeId[3] = (char) ((hostId & 0x000000ff0000L) >> 16);
00267     node->nodeId[2] = (char) ((hostId & 0x0000ff000000L) >> 24);
00268     // these will be 0, as the returned node is only 32 bits
00269     node->nodeId[1] = 0;
00270     node->nodeId[0] = 0;
00271 }
00272 
00273 
00274 /*------------------------------------------------------------------------------
00275  *  Generate a random number
00276  *----------------------------------------------------------------------------*/
00277 uint16_t
00278 Uuid :: trueRandom(void)                                    throw ()
00279 {
00280     static bool inited = false;
00281     UuidTime    timeNow;
00282 
00283     if (!inited) {
00284         getSystemTime(&timeNow);
00285         timeNow = timeNow/UUIDS_PER_TICK;
00286         srand((unsigned int)(((timeNow >> 32) ^ timeNow)&0xffffffff));
00287         inited = true;
00288     };
00289 
00290     return rand();
00291 }
00292 
00293 
00294 /*------------------------------------------------------------------------------
00295  *  Compare two ids.
00296  *----------------------------------------------------------------------------*/
00297 bool
00298 Uuid :: compare(const Uuid    & id1,
00299                 const Uuid    & id2)                        throw ()
00300 {
00301     if (!(id1.timeLow == id2.timeLow
00302        && id1.timeMid == id2.timeMid
00303        && id1.timeHiAndVersion == id2.timeHiAndVersion
00304        && id1.clockSeqHiAndReserved == id2.clockSeqHiAndReserved
00305        && id1.clockSeqLow == id2.clockSeqLow)) {
00306         
00307         return false;
00308     }
00309 
00310     for (int i = 0; i < 6; ++i) {
00311         if (id1.node[i] != id2.node[i]) {
00312             return false;
00313         }
00314     }
00315 
00316     return true;
00317 }
00318 

Generated on Sat Sep 22 02:00:29 2007 for Campcaster by  1.4.7