UUID.cpp

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

Generated on Tue Feb 2 17:18:44 2010 for ACE by  doxygen 1.4.7