UUID.cpp File Reference

#include "ace/UUID.h"
#include "ace/Guard_T.h"
#include "ace/Log_Msg.h"
#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_string.h"
#include "ace/OS_NS_sys_time.h"
#include "ace/OS_NS_netdb.h"
#include "ace/OS_NS_unistd.h"
#include "ace/ACE.h"
Include dependency graph for UUID.cpp:

Go to the source code of this file.

Functions

 ACE_RCSID (ace, UUID,"$Id: UUID.cpp 85376 2009-05-18 17:12:47Z shuston $") 1 namespace ACE_Utils

Function Documentation

ACE_RCSID ( ace  ,
UUID  ,
"$Id: UUID.cpp 85376 2009-05-18 17:12:47Z shuston $"   
)

Todo:
We should create an UUID_Ex class for UUIDs that contain the thread id and process id.

Special case for the nil UUID.

Support versions 1, 3, and 4 only

Obtain a new timestamp. If UUID's are being generated too quickly the clock sequence will be incremented

ACE_Time_Value is in POSIX time, seconds since Jan 1, 1970. UUIDs use time in 100ns ticks since 15 October 1582. The difference is: 15 Oct 1582 - 1 Jan 1600: 17 days in Oct, 30 in Nov, 31 in Dec + 17 years and 4 leap days (1584, 88, 92 and 96) 1 Jan 1600 - 1 Jan 1900: 3 centuries + 73 leap days ( 25 in 17th cent. and 24 each in 18th and 19th centuries) 1 Jan 1900 - 1 Jan 1970: 70 years + 17 leap days. This adds up, in days: (17+30+31+365*17+4)+ (365*300+73)+ (365*70+17) or 122192928000000000U (0x1B21DD213814000) 100 ns ticks.

Get the time of day, convert to 100ns ticks then add the offset.

Definition at line 18 of file UUID.cpp.

00020                : UUID.cpp 85376 2009-05-18 17:12:47Z shuston $")
00021 
00022 
00023 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00024 
00025 namespace ACE_Utils
00026 {
00027   // NIL version of the UUID
00028   const UUID UUID::NIL_UUID;
00029 
00030   UUID::UUID (const ACE_CString& uuid_string)
00031   {
00032     this->init ();
00033     this->from_string_i (uuid_string);
00034   }
00035 
00036   const UUID &
00037   UUID::operator = (const UUID & rhs)
00038   {
00039     if (this == &rhs)
00040       return *this;
00041 
00042     // Reset the string version of the UUID a string version
00043     // exist, and the UUID is not equal to the old UUID.
00044     if (0 != this->as_string_.get ())
00045       {
00046         if (0 == rhs.as_string_.get () || *this != rhs)
00047           this->as_string_.reset ();
00048       }
00049 
00050     // Copy the contents of the UUID.
00051     ACE_OS::memcpy (&this->uuid_, &rhs.uuid_, BINARY_SIZE);
00052 
00053     /// @todo We should create an UUID_Ex class for UUIDs that
00054     ///       contain the thread id and process id.
00055     this->thr_id_ = rhs.thr_id_;
00056     this->pid_ = rhs.pid_;
00057 
00058     return *this;
00059   }
00060 
00061   const ACE_CString * UUID::to_string (void) const
00062   {
00063     // Compute the string representation only once.
00064     if (0 != this->as_string_.get ())
00065       return this->as_string_.get ();
00066 
00067     // Get a buffer exactly the correct size. Use the nil UUID as a
00068     // gauge.  Don't forget the trailing nul.
00069     ACE_Auto_Array_Ptr <char> auto_clean;
00070     size_t UUID_STRING_LENGTH = 36 + thr_id_.length () + pid_.length ();
00071     char *buf = 0;
00072 
00073     if (36 == UUID_STRING_LENGTH)
00074       {
00075         ACE_NEW_RETURN (buf,
00076                         char[UUID_STRING_LENGTH + 1],
00077                         0);
00078 
00079         // Let the auto array pointer manage the buffer.
00080         auto_clean.reset (buf);
00081 
00082         ACE_OS::sprintf (buf,
00083                          "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
00084                          this->uuid_.time_low_,
00085                          this->uuid_.time_mid_,
00086                          this->uuid_.time_hi_and_version_,
00087                          this->uuid_.clock_seq_hi_and_reserved_,
00088                          this->uuid_.clock_seq_low_,
00089                          (this->uuid_.node_.node_ID ()) [0],
00090                          (this->uuid_.node_.node_ID ()) [1],
00091                          (this->uuid_.node_.node_ID ()) [2],
00092                          (this->uuid_.node_.node_ID ()) [3],
00093                          (this->uuid_.node_.node_ID ()) [4],
00094                          (this->uuid_.node_.node_ID ()) [5]);
00095       }
00096     else
00097       {
00098         UUID_STRING_LENGTH += 2; //for '-'
00099         ACE_NEW_RETURN (buf,
00100                         char[UUID_STRING_LENGTH + 1],
00101                         0);
00102 
00103         // Let the auto array pointer manage the buffer.
00104         auto_clean.reset (buf);
00105 
00106         ACE_OS::sprintf (buf,
00107                          "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x-%s-%s",
00108                          this->uuid_.time_low_,
00109                          this->uuid_.time_mid_,
00110                          this->uuid_.time_hi_and_version_,
00111                          this->uuid_.clock_seq_hi_and_reserved_,
00112                          this->uuid_.clock_seq_low_,
00113                          (this->uuid_.node_.node_ID ()) [0],
00114                          (this->uuid_.node_.node_ID ()) [1],
00115                          (this->uuid_.node_.node_ID ()) [2],
00116                          (this->uuid_.node_.node_ID ()) [3],
00117                          (this->uuid_.node_.node_ID ()) [4],
00118                          (this->uuid_.node_.node_ID ()) [5],
00119                          thr_id_.c_str (),
00120                          pid_.c_str ());
00121       }
00122 
00123     // Save the string.
00124     ACE_CString * as_string = 0;
00125 
00126     ACE_NEW_RETURN (as_string,
00127                     ACE_CString (buf, UUID_STRING_LENGTH),
00128                     0);
00129 
00130     this->as_string_.reset (as_string);
00131     return this->as_string_.get ();
00132   }
00133 
00134   void
00135   UUID::from_string_i (const ACE_CString& uuid_string)
00136   {
00137     if (uuid_string.length () < NIL_UUID.to_string ()->length ())
00138       {
00139         ACE_ERROR ((LM_ERROR,
00140                     "%N ACE_UUID::from_string_i - "
00141                     "IllegalArgument (incorrect string length)\n"));
00142         return;
00143       }
00144 
00145     /// Special case for the nil UUID.
00146     if (uuid_string == *NIL_UUID.to_string ())
00147       {
00148         *this = NIL_UUID;
00149         return;
00150       }
00151 
00152     unsigned int time_low;
00153     unsigned int time_mid;
00154     unsigned int time_hi_and_version;
00155     unsigned int clock_seq_hi_and_reserved;
00156     unsigned int clock_seq_low;
00157     unsigned int node [UUID_Node::NODE_ID_SIZE];
00158     char thr_pid_buf [BUFSIZ];
00159 
00160     if (uuid_string.length () == NIL_UUID.to_string ()->length ())
00161       {
00162         // This might seem quite strange this being in ACE, but it
00163         // seems to be a bit difficult to write a facade for ::sscanf
00164         // because some compilers dont support vsscanf, including
00165         // MSVC. It appears that most platforms support sscanf though
00166         // so we need to use it directly.
00167         const int nScanned =
00168 #if defined (ACE_HAS_TR24731_2005_CRT)
00169           sscanf_s (
00170 #else
00171           ::sscanf (
00172 #endif /* ACE_HAS_TR24731_2005_CRT */
00173                    uuid_string.c_str (),
00174                    "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
00175                    &time_low,
00176                    &time_mid,
00177                    &time_hi_and_version,
00178                    &clock_seq_hi_and_reserved,
00179                    &clock_seq_low,
00180                    &node[0],
00181                    &node[1],
00182                    &node[2],
00183                    &node[3],
00184                    &node[4],
00185                    &node[5]
00186                    );
00187 
00188         if (nScanned != 11)
00189           {
00190             ACE_DEBUG ((LM_DEBUG,
00191                         "UUID::from_string_i - "
00192                         "IllegalArgument (invalid string representation)\n"));
00193             return;
00194           }
00195       }
00196     else
00197       {
00198         const int nScanned =
00199 #if defined (ACE_HAS_TR24731_2005_CRT)
00200           sscanf_s (uuid_string.c_str (),
00201                     "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
00202                     &time_low,
00203                     &time_mid,
00204                     &time_hi_and_version,
00205                     &clock_seq_hi_and_reserved,
00206                     &clock_seq_low,
00207                     &node[0],
00208                     &node[1],
00209                     &node[2],
00210                     &node[3],
00211                     &node[4],
00212                     &node[5],
00213                     thr_pid_buf,
00214                     BUFSIZ
00215                     );
00216 #else
00217           ::sscanf (uuid_string.c_str (),
00218                     "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
00219                     &time_low,
00220                     &time_mid,
00221                     &time_hi_and_version,
00222                     &clock_seq_hi_and_reserved,
00223                     &clock_seq_low,
00224                     &node[0],
00225                     &node[1],
00226                     &node[2],
00227                     &node[3],
00228                     &node[4],
00229                     &node[5],
00230                     thr_pid_buf
00231                     );
00232 #endif /* ACE_HAS_TR24731_2005_CRT */
00233 
00234         if (nScanned != 12)
00235           {
00236             ACE_DEBUG ((LM_DEBUG,
00237                         "ACE_UUID::from_string_i - "
00238                         "IllegalArgument (invalid string representation)\n"));
00239             return;
00240           }
00241       }
00242 
00243     this->uuid_.time_low_ = static_cast<ACE_UINT32> (time_low);
00244     this->uuid_.time_mid_ = static_cast<ACE_UINT16> (time_mid);
00245     this->uuid_.time_hi_and_version_ = static_cast<ACE_UINT16> (time_hi_and_version);
00246     this->uuid_.clock_seq_hi_and_reserved_ = static_cast<u_char> (clock_seq_hi_and_reserved);
00247     this->uuid_.clock_seq_low_ = static_cast<u_char> (clock_seq_low);
00248 
00249     for (size_t i = 0; i < UUID_Node::NODE_ID_SIZE; ++ i)
00250       this->uuid_.node_.node_ID ()[i] = static_cast <u_char> (node[i]);
00251 
00252     // Support varient 10- only
00253     if ((this->uuid_.clock_seq_hi_and_reserved_ & 0xc0) != 0x80 &&
00254         (this->uuid_.clock_seq_hi_and_reserved_ & 0xc0) != 0xc0)
00255       {
00256         ACE_DEBUG ((LM_DEBUG,
00257                     "ACE_UUID::from_string_i - "
00258                     "IllegalArgument (unsupported variant)\n"));
00259         return;
00260       }
00261 
00262     /// Support versions 1, 3, and 4 only
00263     ACE_UINT16 V1 = this->uuid_.time_hi_and_version_;
00264 
00265     if ((V1 & 0xF000) != 0x1000 &&
00266         (V1 & 0xF000) != 0x3000 &&
00267         (V1 & 0xF000) != 0x4000)
00268       {
00269         ACE_DEBUG ((LM_DEBUG,
00270                     "ACE_UUID::from_string_i - "
00271                     "IllegalArgument (unsupported version)\n"));
00272         return;
00273       }
00274 
00275     if ((this->uuid_.clock_seq_hi_and_reserved_ & 0xc0) == 0xc0)
00276       {
00277         if (uuid_string.length () == NIL_UUID.to_string ()->length ())
00278           {
00279             ACE_DEBUG ((LM_DEBUG,
00280                       "ACE_UUID::from_string_i - "
00281                         "IllegalArgument (Missing Thread and Process Id)\n"));
00282             return;
00283           }
00284         ACE_CString thr_pid_str (thr_pid_buf);
00285         ssize_t pos = static_cast<ssize_t> (thr_pid_str.find ('-'));
00286         if (pos == -1)
00287           ACE_DEBUG ((LM_DEBUG,
00288                       "ACE_UUID::from_string_i - "
00289                       "IllegalArgument (Thread and Process Id format incorrect)\n"));
00290 
00291         this->thr_id_ = thr_pid_str.substr (0, pos);
00292         this->pid_ = thr_pid_str.substr (pos+1, thr_pid_str.length ()-pos-1);
00293       }
00294   }
00295 
00296   UUID_Generator::UUID_Generator (void)
00297     : time_last_ (0),
00298       destroy_lock_ (true),
00299       is_init_ (false)
00300   {
00301     ACE_NEW (lock_, ACE_SYNCH_MUTEX);
00302     this->init ();
00303   }
00304 
00305   UUID_Generator::~UUID_Generator (void)
00306   {
00307     if (destroy_lock_)
00308       delete lock_;
00309   }
00310 
00311   void
00312   UUID_Generator::init (void)
00313   {
00314     if (this->is_init_)
00315       return;
00316 
00317     ACE_OS::macaddr_node_t macaddress;
00318     int result = ACE_OS::getmacaddress (&macaddress);
00319 
00320     UUID_Node::Node_ID node_id;
00321 
00322     if (-1 != result)
00323       {
00324         ACE_OS::memcpy (node_id,
00325                         macaddress.node,
00326                         UUID_Node::NODE_ID_SIZE);
00327       }
00328     else
00329       {
00330         node_id [0] = static_cast<u_char> (ACE_OS::rand ());
00331         node_id [1] = static_cast<u_char> (ACE_OS::rand ());
00332         node_id [2] = static_cast<u_char> (ACE_OS::rand ());
00333         node_id [3] = static_cast<u_char> (ACE_OS::rand ());
00334         node_id [4] = static_cast<u_char> (ACE_OS::rand ());
00335         node_id [5] = static_cast<u_char> (ACE_OS::rand ());
00336       }
00337 
00338     this->get_timestamp (time_last_);
00339 
00340     {
00341       ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, *lock_);
00342       uuid_state_.timestamp = time_last_;
00343 
00344       ACE_OS::memcpy (uuid_state_.node.node_ID (),
00345                       node_id,
00346                       UUID_Node::NODE_ID_SIZE);
00347     }
00348 
00349     this->is_init_ = true;
00350   }
00351 
00352   void
00353   UUID_Generator::
00354   generate_UUID (UUID& uuid, ACE_UINT16 version, u_char variant)
00355   {
00356     UUID_Time timestamp;
00357     ACE_UINT16 clock_sequence;
00358 
00359     this->get_timestamp_and_clocksequence (timestamp,
00360                                            clock_sequence);
00361 
00362     // Construct a Version 1 UUID with the information in the arguements.
00363     uuid.time_low (static_cast<ACE_UINT32> (timestamp & 0xFFFFFFFF));
00364     uuid.time_mid (static_cast<ACE_UINT16> ((timestamp >> 32) & 0xFFFF));
00365 
00366     ACE_UINT16 tHAV = static_cast<ACE_UINT16> ((timestamp >> 48) & 0xFFFF);
00367     tHAV |= (version << 12);
00368     uuid.time_hi_and_version (tHAV);
00369 
00370     u_char cseqHAV;
00371     uuid.clock_seq_low (static_cast<u_char> (clock_sequence & 0xFF));
00372     cseqHAV = static_cast<u_char> ((clock_sequence & 0x3f00) >> 8);
00373     uuid_state_.timestamp = timestamp;
00374 
00375     cseqHAV |= variant;
00376     uuid.clock_seq_hi_and_reserved (cseqHAV);
00377     uuid.node (uuid_state_.node);
00378 
00379     if (variant == 0xc0)
00380       {
00381         ACE_Thread_ID thread_id;
00382         char buf [BUFSIZ];
00383         thread_id.to_string (buf);
00384         uuid.thr_id (buf);
00385 
00386         ACE_OS::sprintf (buf,
00387                          "%d",
00388                          static_cast<int> (ACE_OS::getpid ()));
00389         uuid.pid (buf);
00390       }
00391   }
00392 
00393   UUID*
00394   UUID_Generator::generate_UUID (ACE_UINT16 version, u_char variant)
00395   {
00396     UUID* uuid;
00397     ACE_NEW_RETURN (uuid,
00398                     UUID,
00399                     0);
00400 
00401     this->generate_UUID (*uuid, version, variant);
00402     return uuid;
00403   }
00404 
00405   /// Obtain a new timestamp. If UUID's are being generated too quickly
00406   /// the clock sequence will be incremented
00407   void
00408   UUID_Generator::get_timestamp (UUID_Time& timestamp)
00409   {
00410     ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
00411 
00412     this->get_systemtime (timestamp);
00413 
00414     // Account for the clock being set back. Increment the clock /
00415     // sequence.
00416     if (timestamp <= time_last_)
00417       {
00418         uuid_state_.clock_sequence = static_cast<ACE_UINT16>
00419           ((uuid_state_.clock_sequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
00420       }
00421     // If the system time ticked since the last UUID was
00422     // generated. Set / the clock sequence back.
00423     else if (timestamp > time_last_)
00424       {
00425         uuid_state_.clock_sequence = 0;
00426       }
00427 
00428     time_last_ = timestamp;
00429   }
00430 
00431   void
00432   UUID_Generator::get_timestamp_and_clocksequence (UUID_Time& timestamp,
00433                                                    ACE_UINT16& clock_sequence)
00434   {
00435     ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
00436 
00437     this->get_systemtime (timestamp);
00438 
00439     // Account for the clock being set back. Increment the clock /
00440     // sequence.
00441     if (timestamp <= time_last_)
00442       uuid_state_.clock_sequence = static_cast<ACE_UINT16> ((uuid_state_.clock_sequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
00443 
00444     // If the system time ticked since the last UUID was
00445     // generated. Set / the clock sequence back.
00446     else if (timestamp > time_last_)
00447       uuid_state_.clock_sequence = 0;
00448 
00449     time_last_ = timestamp;
00450     clock_sequence = uuid_state_.clock_sequence;
00451   }
00452 
00453   /**
00454    * ACE_Time_Value is in POSIX time, seconds since Jan 1, 1970. UUIDs use
00455    * time in 100ns ticks since 15 October 1582. The difference is:
00456    *   15 Oct 1582 - 1 Jan 1600: 17 days in Oct, 30 in Nov,  31 in Dec +
00457    *       17 years and 4 leap days (1584, 88, 92 and 96)
00458    *   1 Jan 1600 - 1 Jan 1900: 3 centuries + 73 leap days ( 25 in 17th cent.
00459    *       and 24 each in 18th and 19th centuries)
00460    *   1 Jan 1900 - 1 Jan 1970: 70 years + 17 leap days.
00461    * This adds up, in days: (17+30+31+365*17+4)+ (365*300+73)+ (365*70+17) or
00462    * 122192928000000000U (0x1B21DD213814000) 100 ns ticks.
00463    */
00464   void
00465   UUID_Generator::get_systemtime (UUID_Time & timestamp)
00466   {
00467     const UUID_Time timeOffset =
00468 #if defined (ACE_LACKS_UNSIGNEDLONGLONG_T)
00469       ACE_U_LongLong (ACE_INT64_LITERAL (0x1B21DD213814000));
00470 #elif defined (ACE_LACKS_LONGLONG_T)
00471       ACE_U_LongLong (0x13814000u, 0x1B21DD2u);
00472 #else
00473       ACE_UINT64_LITERAL (0x1B21DD213814000);
00474 #endif  /* ACE_LACKS_UNSIGNEDLONGLONG_T */
00475 
00476     /// Get the time of day, convert to 100ns ticks then add the offset.
00477     ACE_Time_Value now = ACE_OS::gettimeofday ();
00478     ACE_UINT64 time;
00479     now.to_usec (time);
00480     time = time * 10;
00481     timestamp = time + timeOffset;
00482   }
00483 
00484   ACE_SYNCH_MUTEX*
00485   UUID_Generator::lock (void)
00486   {
00487     return this->lock_;
00488   }
00489 
00490   void
00491   UUID_Generator::lock (ACE_SYNCH_MUTEX* lock, bool release_lock)
00492   {
00493     if (this->destroy_lock_)
00494       delete this->lock_;
00495 
00496     this->lock_ = lock;
00497     this->destroy_lock_ = release_lock;
00498   }
00499 }

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Sun Nov 22 23:13:26 2009 for ACE by  doxygen 1.6.1